2014-11-24 11 views
33

Swift'de bir iOS uygulamasında çalışıyorum (çoğu Objective-C'den taşındı). Çekirdek Verileri kullanıyorum ve modelimden otomatik olarak oluşturulan sınıflara işlevsellik eklemek için uzantıları kullanmaya çalışıyorum. Objective-C'de hazırladığım bir şey, A sınıfındaki bir kategoride bir yöntem eklemek ve bu yöntemi, B sınıfındaki (A'dan türetilen) bir kategoride geçersiz kılmaktı ve aynı şeyi Swift'de yapmayı umuyordum. Bir süreSwift'deki uzantılar arasında geçersiz kılınabilir veya değil mi? (Derleyici karışık görünüyor!)

şimdi Projemde aşağıdaki kodu yaşadım (ve bu sadece bir örnektir) ve ben işlev henüz kullanmadıysanız bile, derleyici gayet güzel bu kodu derleme çalıştı:

// From CellType.swift -- NOTE: Imports from Foundation and CoreData 
@objc(CellType) 
class CellType: NSManagedObject { 
    @NSManaged var maxUses: NSNumber 
    @NSManaged var useCount: NSNumber 
    // Other properties removed for brevity 
} 


// From SwitchCellType.swift -- NOTE: Imports from Foundation and CoreData 
@objc(SwitchCellType) 
class SwitchCellType: CellType { 
    @NSManaged var targetCellXIndex: NSNumber 
    @NSManaged var targetCellYIndex: NSNumber 
    @NSManaged var targetCellType: CellType 
    // Other properties removed for brevity 
} 


// From CellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData 
extension CellType 
{ 
    var typeLabel : String { get { return "Empty"; } } 
    func isEqualToType(otherCellType : CellType) -> Bool 
    { 
     return (self.typeLabel == otherCellType.typeLabel && 
      self.maxUses.isEqualToNumber(otherCellType.maxUses) && 
      self.useCount.isEqualToNumber(otherCellType.useCount)); 
    } 
    // Code removed for brevity 
} 


// From SwitchCellTypeLogic.swift -- NOTE: Imports from Foundation and CoreData 
extension SwitchCellType // YES, this compiles with the overrides! 
{ 
    override var typeLabel : String { get { return "Switch"; } } 
    override func isEqualToType(otherCellType : CellType) -> Bool 
    { 
     var answer = false; 
     if let otherSwitchCellType = otherCellType as? SwitchCellType 
     { 
      answer = super.isEqualToType(otherCellType) && 
       self.targetCellXIndex.isEqualToNumber(otherSwitchCellType.targetCellXIndex) && 
       self.targetCellYIndex.isEqualToNumber(otherSwitchCellType.targetCellYIndex) && 
       self.targetCellType.isEqualToType(otherSwitchCellType.targetCellType); 
     } 
     return answer; 
    } 
    // Code removed for brevity 
} 

Umarım bir tür Swift uzmanı zaten benim sorunumu görüyor, ancak işte bu konuyla ilgili nasıl öğrendim: Son zamanlarda, türlerde yerleşik olmayan parametreler ve/veya dönüş değerleri olan yöntemleri kullanarak benzer işlevleri eklemeyi denedim, ancak Bu hatayı almaya başladım: Uzantılardaki bildirimler henüz geçersiz sayılmaz.

Bu sorunu araştırmak için ben gayet güzel derlemek istiyorsunuz düşünmek benim hızlı dosyalardan biri için aşağıdaki eklendi: Benim için sürpriz

class A 
{ 
} 

class B : A 
{ 
} 

extension A 
{ 
    var y : String { get { return "YinA"; } } 
} 

extension B 
{ 
    override var y : String { get { return "YinB"; } } // Compiler error (see below) -- What?? 
} 

, ben aynı derleyici hatası aldı (uzantılarında Beyannameler henüz geçersiz kılamaz). Ne? Ama ben bu derleyiciyi derleyici hataları olmadan birkaç kez kullandım.

Sorular: İlk olarak, bazı durumlarda çalışmasının gerektiği, ancak diğer durumlarda değil, uzantıların geçersiz kılınmasıyla ilgili bazı kurallar var mıdır? İkincisi (ve daha da rahatsız edici), neden Swift derleyicisinin bu kadar tutarsız olduğu görünüyor? Burada neyi özlüyorum? Swift'e olan inancımı geri kazanmama yardım edin.

GÜNCELLEME: Martin R tarafından doğru cevap belirtildiği gibi

, sürece (1) yalnızca sınıfları dahil olarak (Xcode 6.1 üzerinden 1.1) Swift geçerli sürümünde yöntemlerini geçersiz kılabilir görünüyor NSObject türetilmiştir ve (2) inout değiştirici kullanmayın. İşte bazı örnekler verilmiştir:

class A : NSObject { } 

class B : A { } 

class SubNSObject : NSObject {} 
class NotSubbed {} 
enum SomeEnum { case c1, c2; } 

extension A 
{ 
    var y : String { get { return "YinA"; } } 
    func f() -> A { return A(); } 
    func g(val: SubNSObject, test: Bool = false) { } 

    func h(val: NotSubbed, test: Bool = false) { } 
    func j(val: SomeEnum) { } 
    func k(val: SubNSObject, inout test: Bool) { } 
} 

extension B 
{ 
    // THESE OVERIDES DO COMPILE: 
    override var y : String { get { return "YinB"; } } 
    override func f() -> A { return A(); } 
    override func g(val: SubNSObject, test: Bool) { } 

    // THESE OVERIDES DO NOT COMPILE: 
    //override func h(val: NotSubbed, test: Bool = false) { } 
    //override func j(val: SomeEnum) { } 
    //override func k(val: SubNSObject, inout test: Bool) { } 

} 

cevap

38

Bir uzantısı yöntemleri ve özellikleri ağır basan tek Objective-C uyumlu yöntemleri ve özellikleri için akım Swift (Swift 1.1/Xcode 6.1) ile çalışıyor görünüyor. Bir sınıf NSObject elde edildiği takdirde

sonra tüm üyeleri (mümkünse, aşağıya bakınız) Amaç-C otomatik olarak kullanılabilir. Bu nedenle,

örnek kodunuz beklendiği gibi derler ve çalışır. Kod Verileri Uzantınız, NSManagedObjectNSObject'un bir alt sınıfı olduğundan, geçersiz kılar.

Alternatif olarak, bir yöntem veya özellik için @objc niteliğini kullanabilir: Amaç-C belirtilemeyeceği

class A { } 

class B : A { } 

extension A 
{ 
    @objc var y : String { get { return "YinA" } } 
} 

extension B 
{ 
    @objc override var y : String { get { return "YinB" } } 
} 

Yöntemi @objc işaretli edilemez ve bir alt uzantısında iptal edilemez.Bu, örneğin inout parametresine veya enum tipinin parametrelerine sahip yöntemlerine uygulanır.

+0

Doğru cevap bu gibi görünüyor. Ayrıca, inout'u kullanan yöntemleri geçersiz kılabilirsiniz. Bunu kendim kontrol ettim ve bazı basit örnekler vermek için soruma bir güncelleme ekleyeceğim. Teşekkürler! – FTLPhysicsGuy

+0

@FTLPhysicsGuy: Haklısın ve cevabım eksikti. Gerçek ölçüt, yöntemin veya özelliklerin Objektif-C uyumlu olup olmadığıdır. Cevabını buna göre güncelledim. –

+1

Aynı sorunu xCode 7.2 kullanarak aldım. Mesajda "uzantılardaki bildirimlerin henüz geçersiz kılınamayacağını" söylüyor. Bu benim için çok büyük bir problem, çünkü UICollectionViewCell ve UICollectionReusableView için hem alt sınıflarında daha sonra geçersiz kılınabilecek bazı yöntemleri kullanmak istiyorum. – Darius

0

Bunu Xcode9'da deneyimledim. Xcode'un kapatılması ve yeniden açılması benim için çalıştı. Derleyicide muhtemelen bir hata.