Swift 方法重写 报错 Overriding non-@objc declarations from extensions is not supported。
class Base {
func show1() {
}
}
extension Base {
func show2() {
}
}
class AA: Base {
override func show2() {
}
}
extension AA {
override func show1() {
}
}
当AA类的extension 重写 父类 Base 中的 show1 方法 或者 AA类在主体重写父类extension中的show2方法的时候, 编译器会提示错误 Overriding non-@objc declarations from extensions is not supported。
正确写法
class Base {
@objc dynamic func show1() {
}
}
extension Base {
@objc func show2() {
}
}
class AA: Base {
override func show2() {
}
}
extension AA {
override func show1() {
}
}
如果主体方法加上 @objc dynamic 子类的extension 就可以重写了。
父类的extension中的方法加 @objc 子类的主体就可以重写了。
这个是为什么那?
Swift 目前方法调度 分为三种调度 直接调度,表调度,消息调度
直接调度
直接调用方法声明 速度最快。但是不能动态的支持子类
表调度
一般用函数地址的数组来储存类中方法的声明
子类中Vtable 会添加父类的方法声明。
消息调度
OC 语言 就是采用这种方法调度的。通过msg_send() 方法来从类中或者父类中查询方法。这个调度比较慢,但是有缓存机制。可以提升效率。具有很好的灵活性。
Swift对应调度表
| 对象 | Static | VTable | Witness Table | Message |
|---|---|---|---|---|
| Swift struct | 默认行为 | N/A | : protocol | N/A |
| Swift Class | final extension | 默认行为 | : protocol | dynamic |
| 继承NSObject | final extension | 默认行为 | : protocol | dynamic |
| Protocol | extension | 默认行为 | N/A | : NSObjectProtocol @objc |
extension 中的方法默认是直接调度。
通过方法调度方式可以知道。
直接调度是不能被继承的。
表调度只能被子类主体继承。
那么如果要实现开头的方法重写 只有让方法是消息调度。
通过 在主体方法 加 @objc dynamic 关键字 和 extension 方法中添加 @objc,来改变方法的调度为消息调度。