在Swift 4中,无法覆盖扩展声明

时间:2017-10-04 12:11:10

标签: ios swift swift4 extension-methods

我最近将代码迁移到 Swift 4 。我面临的问题是扩展,即:

  

扩展声明无法覆盖

我已经阅读了多篇报道此问题的帖子。但他们都没有接受下面描述的情景:

class BaseCell: UITableViewCell
{
    //Some code here...
}

extension BaseCell
{
    func isValid() -> String?
    {
        //Some code here...
    }
}

class SampleCell: BaseCell
{
    //Some code here...

    override func isValid() -> String? //ERROR..!!!
    {
        //Some code here...
    }
}

根据Apple的说法,

  

扩展程序可以为类型添加新功能,但它们无法覆盖现有功能。

但是在上面的场景中,我没有覆盖扩展中的isValid()方法。它在SampleCell类定义本身中被覆盖。不过,它正在给出错误。

6 个答案:

答案 0 :(得分:10)

  

但是在上面的场景中,我没有覆盖扩展中的方法isValid()

isValid扩展程序中声明。

该错误几乎表明,如果以这种方式声明函数,无法覆盖

该声明对扩展和扩展中的均有效。

答案 1 :(得分:5)

只要您@objc协议,就可以覆盖扩展名中的声明。在Swift 4.2中:

class BaseClass {}
class SubclassOfBaseClass: BaseClass {}

@objc protocol IsValidable {
    func isValid() -> Bool
}

extension BaseClass: IsValidable {
    func isValid() -> Bool { return false }
}

extension SubclassOfBaseClass {
    override func isValid() -> Bool { return !super.isValid() }
}

BaseClass().isValid()           // -> false
SubclassOfBaseClass().isValid() // -> true

答案 2 :(得分:4)

在Swift 3中,如果扩展是从Objective-C(http://blog.flaviocaetano.com/post/this-is-how-to-override-extension-methods/)派生的类,你可以覆盖扩展的功能,但我想现在它在Swift 4中是不可能的。你可以做这样的事情:

protocol Validity {
    func isValid() -> String?
}

class BaseCell: UITableViewCell, Validity {

}

extension Validity
{
    func isValid() -> String? {
        return "false"
    }
}

class SampleCell: BaseCell {

    func isValid() -> String? {
        return "true"
    }
}


let base = BaseCell()
base.isValid() // prints false

let sample = SampleCell()
sample.isValid() // prints true

答案 3 :(得分:3)

我认为这是不言自明的。 声明 FROM 扩展程序无法覆盖

您正在尝试overridefunc isValid() -> String? extension内声明的函数BaseCell,而不是BaseCell类本身。

显然,您无法覆盖在扩展程序中声明的内容。

希望它有用。

答案 4 :(得分:1)

我也有一个Swift 3代码的巨大遗产,使用这个老技巧来实现我想要的,所以当我转移到Swift 4并开始得到这些错误时,我有点心疼。不要害怕,有一个解决方案。

这个错误与Swift 4编译类的方式以及它处理Objective-C类和函数的新方式有关。在Swift 3下,如果一个类是从NSObject派生的,那么该类中的所有变量和函数都将使用Objective-C的动态命名和查找约定。这种方法抑制了Swift优化代码并提高代码性能和大小的能力。

为了克服这些惩罚,在Swift 4中,只有用@objc明确标记的变量和函数才能得到Objective-C处理,其他一切都使用标准的Swift约定:因此错误。

有了这些知识,你的问题的解决方案是将你希望被覆盖的扩展中的函数标记为@objc,然后在子类中覆盖函数,但是记得包含{{ 1}}标记,以便在运行时调用代码。

警告这里有点问题:如果您忘记在@objc中包含@objc,编译器不会抱怨,但您的代码缺少动态查找,所以永远不要在运行时调用。

所以你的代码应该看起来像这样:

override

答案 5 :(得分:0)

它在Swift中无效,但不在Objective-C中。因此,如果您的方法签名允许它(没有objc禁止构造),您可以声明它@objc func myMethod()并在Swift中自由覆盖它。