一尘不染

您能否在Swift中的扩展之间覆盖?(编译器似乎很困惑!)

swift

我一直在开发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) { }

}

阅读 245

收藏
2020-07-07

共1个答案

一尘不染

似乎扩展中的重写方法和属性仅适用于与 Objective-C兼容的 方法和属性,并且与当前的Swift(Swift 1.1 / Xcode
6.1)一起使用。

如果一个类是从中派生的,NSObject那么它的所有成员都可以在Objective-C中自动使用(如果可能,请参见下文)。所以用

class A : NSObject { }

您的示例代码可以编译并按预期工作。您的代码数据扩展名覆盖了工作,因为它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" } }
}

在Objective-C中无法表示的方法不能@objc 在子类扩展中进行标记和覆盖。例如,这适用于具有inout参数或enum类型参数的方法。

2020-07-07