当前位置: 首页 > 面试题库 >

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

濮阳国兴
2023-03-14
问题内容

我一直在开发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中自动使用(如果可能,请参见下文)。所以用

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类型参数的方法。



 类似资料:
  • 问题内容: 我正在尝试使用Swift协议扩展,却发现这种行为令人困惑。您能帮我得到我想要的结果吗? 请参阅代码最后4行的注释。(如果需要,可以将其复制粘贴到Xcode7游乐场)。谢谢!! 问题答案: 简短的答案是协议扩展不执行类多态性。这是有一定道理的,因为协议可以被结构或枚举采用,并且因为我们不希望仅在没有必要的地方采用协议来引入动态调度。 因此,在中,实例变量(可能更准确地写为)并不意味着您认

  • 问题内容: 如果我上课: 我最初以为我可以通过添加扩展名来覆盖子类而无需子类化: 该代码不会编译,但错误说明了该函数,这很有意义。 我的问题是: 是否仍要重写特定类的功能?换句话说,在某些情况下,例如上面的示例中,我可以替换功能吗?如果没有,是否有其他解决方法或方法来实现该行为(可能声明了另一个协议,idk) 现在,我考虑得更多了,我不得不说这是不可能的,因为是什么阻止某人重写任何标准库函数? 问

  • 扩展说明 Java 代码编译器,用于动态生成字节码,加速调用。 扩展接口 org.apache.dubbo.common.compiler.Compiler 扩展配置 自动加载 已知扩展 org.apache.dubbo.common.compiler.support.JdkCompiler org.apache.dubbo.common.compiler.support.JavassistCom

  • 问题内容: 我有一个协议扩展,它过去在swift 2.2之前可以完美地工作。 现在我有一个警告,告诉我使用新的,但是如果我添加它 没有使用Objective-C选择器声明任何方法。 我尝试通过以下几行代码重现该问题,可以轻松将其复制并粘贴到操场上 还有一个建议在协议中附加到该方法,但是如果我这样做,它还会要求我将其添加到实现该方法的类中,但是一旦添加,该类便不再符合该协议,因为它不符合该协议似乎看

  • 我正在开发一个包(模块?)设计为pip安装。该包包含一个C扩展,使用pybind11包装,它链接到其他一些库。 我能够手动编译和链接扩展库,没有问题,但是我无法正确配置我的文件,以便在调用时安装扩展模块。 我一直遵循这段代码(pybind11文档链接到)来配置我的文件,包含在下面。 为完整起见,我的包目录如下所示: 我按如下方式调用pip3安装: (版本检查被禁用,因为机器无法访问互联网)。 我可

  • 问题内容: 如何解决以下错误? 您的PHP安装似乎缺少WordPress所需的MySQL扩展。 我将NAS与telnet连接一起使用。 我安装了FFP 0.7 我在:我对我认为有用的所有内容都未加评论。 以下是我文件的一部分; 悬而未决的问题是,当我运行时,我看到模块MySQLi已激活,但未激活MySQL。 MySQL和PHP和Lighttpd Web服务器一样工作正常。 我同样有phpmyadm