请解释为何此处需@objc关键字才能编译?兼询其与dynamic的差异
关于Swift中@objc关键字的两个问题解答
先看你给出的代码示例:
class MyClass { } extension MyClass { @objc func extensionMethod() { print("A") } } class SubClass: MyClass { override func extensionMethod() { print("B") } }
一、为什么非NSObject子类的extension方法需要@objc才能让子类override?
这得从Swift的方法调度机制说起:
- 类主定义里的方法,默认是动态分发(通过vtable实现),子类可以正常override;
- 但extension中定义的方法,默认是静态分发——编译时就确定了调用关系,这个方法不会被加入到类的动态分发表里,所以子类根本找不到可覆盖的父类方法,编译自然报错。
@objc在这里的核心作用,就是把extension方法从“静态绑定”改成“动态分发”:
- 它会把这个方法暴露给Objective-C运行时,生成对应的Objective-C兼容签名;
- 同时让Swift为这个方法启用基于Objective-C运行时的动态分发逻辑,哪怕你的
MyClass没有显式继承NSObject,Swift也会自动让它适配Objective-C运行时(隐式遵循NSObjectProtocol),这样子类就能识别到这个方法并进行override了。
如果去掉@objc,extension方法是静态绑定,编译器会认为子类的override func extensionMethod()没有对应的父类方法可覆盖,直接抛出编译错误。
二、@objc和dynamic在消息分发上的区别?
两者有联系但功能不同:
- @objc:主要目的是让Swift的方法/属性能被Objective-C代码调用。对于非NSObject子类,它会启用基于Objective-C的动态分发;对于NSObject子类,@objc标记的方法默认是动态分发,但Swift可能会在某些场景下做静态优化(比如能确定调用对象的具体类型时,直接静态绑定,不走消息分发)。
- dynamic:它是@objc的强化版,强制所有调用都必须通过Objective-C消息分发机制,完全禁止Swift的静态优化。这意味着:
- 支持Objective-C的方法交换(method swizzling);
- 哪怕Swift能确定调用对象的类型,也会走消息发送流程;
- 标记dynamic的方法自动隐含@objc,不需要额外添加。
总结一下:@objc是“允许”使用消息分发,而dynamic是“强制”使用消息分发。
内容的提问来源于stack exchange,提问作者Vyacheslav
相关产品推荐
相关产品推荐

