我最近将代码迁移到 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
类定义本身中被覆盖。不过,它正在给出错误。
答案 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 扩展程序无法覆盖
您正在尝试override
在func 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中自由覆盖它。