FTL*_*Guy 33 overriding swift swift-extensions
我一直在使用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
}
Run Code Online (Sandbox Code Playgroud)
希望某种类型的Swift专家已经看到了我的问题,但这里是我发现它的方法:最近我尝试使用具有参数和/或返回值的方法添加类似的功能,这些方法没有内置类型,但我开始得到这个错误:扩展中的声明无法覆盖.
为了探讨这个问题,我将以下内容添加到我的一个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??
}
Run Code Online (Sandbox Code Playgroud)
令我惊讶的是,我收到了相同的编译器错误(扩展中的声明无法覆盖).什么?但是我已经多次使用过这种模式而没有编译器错误.
问题:首先,是否存在关于覆盖扩展的某些规则,以至于在某些情况下它应该起作用,但在其他情况下它不起作用?第二个(而且更令人不安)为什么Swift编译器看起来如此不一致?我在这里错过了什么?请帮助我恢复对Swift的信心.
更新:
正如Martin R的正确答案所述,似乎你可以覆盖当前版本的Swift(1.1通过Xcode 6.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) { }
}
Run Code Online (Sandbox Code Playgroud)
Mar*_*n R 38
似乎扩展中的重写方法和属性仅适用于当前的Swift(Swift 1.1/Xcode 6.1),仅适用于Objective-C兼容的 方法和属性.
如果派生一个类,NSObject
那么它的所有成员都可以在Objective-C中自动获得(如果可能,请参见下文).所以
class A : NSObject { }
Run Code Online (Sandbox Code Playgroud)
您的示例代码编译并按预期工作.您的代码数据扩展覆盖工作,因为它NSManagedObject
是.的子类NSObject
.
或者,您可以将@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" } }
}
Run Code Online (Sandbox Code Playgroud)
在Objective-C中无法表示的方法无法@objc
在子类扩展中标记,也不能覆盖.这适用于例如具有类型的inout
参数或参数的方法enum
.