Ios 在Swift 4中,扩展的声明还不能被覆盖
我最近将代码迁移到了Swift 4。我在扩展方面面临一个问题,即: 扩展的声明还不能被重写 我已经读过多篇文章对这个问题进行了重新分类。但它们中没有一个符合以下描述的情况:Ios 在Swift 4中,扩展的声明还不能被覆盖,ios,swift,swift4,extension-methods,Ios,Swift,Swift4,Extension Methods,我最近将代码迁移到了Swift 4。我在扩展方面面临一个问题,即: 扩展的声明还不能被重写 我已经读过多篇文章对这个问题进行了重新分类。但它们中没有一个符合以下描述的情况: class BaseCell: UITableViewCell { //Some code here... } extension BaseCell { func isValid() -> String? { //Some code here... } } class
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...
}
}
据苹果公司称
扩展可以向类型添加新功能,但不能覆盖现有功能
但是在上面的场景中,我没有覆盖扩展中的方法isValid()
。它在SampleCell
类定义本身中被重写。尽管如此,它还是给出了错误
但是在上面的场景中,我并没有覆盖扩展中的方法isValid()
isValid
在扩展名中声明
该错误几乎表明,如果函数以这种方式声明,它不能被重写
该语句对扩展名中的和扩展名中的都有效,我认为这是不言自明的。 来自扩展的声明还不能被覆盖 您正试图
重写函数func isValid()->String?
,该函数是在BaseCell
的扩展中声明的,而不是BaseCell
类本身
很明显,您不能覆盖在扩展中声明的内容
希望有帮助。在Swift 3中,如果扩展属于从Objective-C()派生的类,则可以重写扩展函数,但我想现在在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
它在Swift中无效,但在Objective-C中无效。因此,如果您的方法签名允许它(没有禁止的objc构造),您可以声明它@objc func myMethod()
,并在Swift中自由重写它。我也有大量的Swift 3代码,它们使用了这个旧技巧来实现我想要的目标,所以当我转到Swift 4并开始出现这些错误时,我有点沮丧。不要害怕,有解决办法
这个错误与Swift 4编译类的方式以及它处理Objective-C类和函数的新方式有关。在Swift 3中,如果一个类是从NSObject派生的,那么该类中的所有变量和函数都将使用Objective-C的动态命名和查找约定。这种方法抑制了Swift优化代码、提高代码性能和大小的能力
为了克服这些惩罚,在Swift 4中,只有显式标记为@objc
的变量和函数才能得到Objective-C处理,其他所有内容都使用标准Swift约定:因此产生了错误
有了这些知识,问题的解决方案是将扩展中希望重写的函数标记为@objc
,然后在子类中重写该函数,但请记住包含@objc
标记,以便在运行时调用代码
警告:如果您忘记在覆盖
中包含@objc
,编译器不会抱怨,但您的代码缺少动态查找,因此在运行时永远不会被调用
因此,您的代码应该有点像这样:
class BaseCell: UITableViewCell {
//Some code here...
}
extension BaseCell {
@objc func isValid() -> String? {
//Some code here...
}
}
class SampleCell: BaseCell {
//Some code here...
@objc override func isValid() -> String? {
//Some code here...
}
}
只要您@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
你不想用extension BaseCell
而不是extension SampleCell
?@4kman我错了。它是BaseCell而不是SampleCell。“但是在上面的场景中,我没有覆盖extension中的方法isValid()
。,是的,您将尝试重写它。此语句对“from extension”和“in extension”都有效吗?是的。无论如何,在扩展中重写函数没有多大意义,因为这应该通过子类化来完成。实际上,为了更好地理解和可读性,我已经基于功能创建了一个类的多个扩展。现在我得到了这个错误。要解决这个问题,我必须将所有代码移到一个块中。这背后的原因是什么?为什么不允许这样做?这是一个很好的观点,在Swift 3中被支持,但在Swift 4中不再支持。那些将Swift 3项目迁移到Swift 4的人可能会看到这个问题,并首先思考他们的代码是如何编译的。只是Swift 4减少了@objc
推断。如果您声明函数@objc
,它将像以前一样工作。