Swift 5.0中继承NSObject的类加@objc是否有语义差异及额外功能?
关于Swift中@objc修饰NSObject子类的语义差异与额外功能
嘿,这个问题问到点子上了——虽然X和Y都继承自NSObject,但@objc的存在确实给它们带来了关键的语义差异,也附加了不少Objective-C相关的功能。我来给你详细拆解:
一、两个类的语义差异(Swift视角)
从Swift代码的运行和使用场景来看,X和Y主要有这些区别:
- Objective-C运行时可见性:
@objc class X: NSObject会把整个类暴露给Objective-C运行时,而class Y: NSObject默认只在Swift环境中可见,不会主动暴露给OC。举个例子:// 可以成功获取X类的OC运行时信息 if let xClass = NSClassFromString("YourModule.X") as? X.Type { let xInstance = xClass.init() xInstance.x = 10 } // 无法获取Y类,返回nil let yClass = NSClassFromString("YourModule.Y") - 属性/方法的OC暴露规则:
X类中所有Objective-C兼容类型的属性(比如这里的var x = 0)会自动被隐式标记为@objc,可以被OC代码直接访问;而Y类的var y = 0默认只能在Swift中使用,OC代码看不到这个属性,除非你给y单独加上@objc修饰。 - Selector与OC API兼容性:
当你需要使用依赖Objective-C选择器的Swift API时(比如#selector、NSTimer、UIButton的点击事件绑定),X类的方法/属性setter可以直接用,Y类的不行。比如:// 对于X类,这行代码合法 let xSelector = #selector(setter: X.x) // 对于Y类,这行代码会报错,因为y未暴露给OC // let ySelector = #selector(setter: Y.y)
二、@objc为NSObject子类添加的额外功能
给继承自NSObject的类加上@objc,本质是让它完全接入Objective-C的运行时生态,带来这些额外能力:
- 跨语言调用支持:OC代码可以
import这个Swift类,创建实例、调用属性和方法,实现Swift与OC的双向交互。 - Objective-C运行时特性支持:
- 可以使用KVC(键值编码):比如
xInstance.setValue(20, forKey: "x")是合法的,但yInstance.setValue(20, forKey: "y")会崩溃,因为y不在OC运行时的键路径列表里。 - 配合
dynamic关键字可以支持KVO(键值观察):虽然@objc本身不开启KVO,但它是dynamic生效的前提,只有被@objc dynamic修饰的属性才能在Swift中正常使用KVO。
- 可以使用KVC(键值编码):比如
- 动态类型识别与操作:可以通过OC运行时的API(比如
class_copyMethodList、objc_getAssociatedObject等)对类进行动态修改和查询,这些操作对未加@objc的Y类是无效的。 - 系统API兼容性:很多UIKit、Foundation的老API依赖Objective-C运行时,比如
UITableViewDataSource的某些方法、NSNotificationCenter的观察者注册,@objc修饰的类可以无缝适配这些API,而未修饰的类可能会出现编译错误或运行时异常。
需要注意的是:从Swift 4开始,默认情况下NSObject子类不会自动暴露给OC,必须显式添加@objc或者@objcMembers(后者会把整个类的所有兼容成员都暴露给OC)。
内容的提问来源于stack exchange,提问作者user2158697
相关产品推荐
相关产品推荐

