我一直在开发Swift中的iOS应用程序(其中大部分已从Objective-C中移出)。我正在使用Core Data,并尝试使用扩展将功能添加到从我的模型自动生成的类中。我在Objective- C中容易做的一件事是在类A的类别中添加一个方法,并在类B的类别(从A派生)中覆盖该方法,我希望在Swift中也能做到这一点。
一段时间以来,我的项目中已有以下代码(这只是一个示例),尽管我尚未使用该功能,但是编译器可以很好地编译此代码:
// 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 }
希望有一些Swift专家已经解决了我的问题,但是这是我发现的方式:最近,我尝试使用具有参数和/或返回值(不是内置类型的方法)的方法来添加类似的功能,但是我开始明白了错误:扩展中的声明无法覆盖。
为了探讨这个问题,我将以下内容添加到了我的一个快速文件中,认为它可以正常编译:
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?? }
令我惊讶的是,我收到了相同的编译器错误(扩展声明无法覆盖)。什么?但是我已经使用了几次该模式,而没有编译器错误。
问题:首先,是否存在某些关于扩展中的覆盖的规则,使得在某些情况下它应该起作用,但在另一些情况下却不起作用?第二(更令人不安的是)为什么Swift编译器似乎如此不一致?我在这里想念什么?请帮助我恢复对Swift的信念。
更新:
正如Martin R在正确答案中指出的那样,似乎您可以覆盖当前版本的Swift(通过Xcode 6.1通过1.1)中的方法,只要它们(1)仅涉及派生自NSObject的类,并且(2)不使用inout修饰符。这里有一些例子:
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) { } }
似乎扩展中的重写方法和属性仅适用于与 Objective-C兼容的 方法和属性,并且与当前的Swift(Swift 1.1 / Xcode 6.1)一起使用。
如果一个类是从中派生的,NSObject那么它的所有成员都可以在Objective-C中自动使用(如果可能,请参见下文)。所以用
NSObject
class A : NSObject { }
您的示例代码可以编译并按预期工作。您的代码数据扩展名覆盖了工作,因为它NSManagedObject是的子类NSObject。
NSManagedObject
另外,您可以将@objc属性用于方法或属性:
class A { } class B : A { } extension A { @objc var y : String { get { return "YinA" } } } extension B { @objc override var y : String { get { return "YinB" } } }
在Objective-C中无法表示的方法不能@objc 在子类扩展中进行标记和覆盖。例如,这适用于具有inout参数或enum类型参数的方法。
@objc
inout
enum