我读过一些像 this one 这样的文章,关于 Swift 中的子类化
NSObject
与仅拥有其原生基础 class
而没有子类化之间的区别。但都是有点老的帖子了,我对这个话题不太清楚。
什么时候应该子类化
NSObject
?子类化和不子类化之间的实际区别是什么?目前 Swift 的推荐是什么?
Apple 关于 NSObject 的文档有以下介绍:
NSObject 是大多数 Objective-C 类层次结构的根类。通过 NSObject,对象继承了运行时系统的基本接口以及作为 Objective-C 对象运行的能力。
正如这表明的那样,每当该类型的实例需要表现得像 Objective-C 对象(或类本身,在某些罕见的情况下)时,您需要为代码中引入的类型创建 NSObject 子类。
我不知道苹果是否提供了关于何时不子类化 NSObject 的超级明确的书面指导,除了建议减少动态调度或使用不依赖于子类化而是协议扩展(即代码)来呈现代码重用范例重用通常更静态调度和值类型友好)。我相信可以公平地说,大多数 Swift 程序员都从 Apple 那里得到了暗示,并且 Swift 语言特性作为标志,在没有上述需求时避免引入基于 NSObject 的类型。 也就是说,作为一般规则,仅在您实际需要 Objective-C 动态性时才引入基于 NSObject 的类型,最常见的是当您需要与 Cocoa API 交互时(尤其是当您的代码与 UI 相关时常见:例如视图控制器、视图) .
正如您链接到的问题的答案中所指出的,Objective-C 风格的活力带来了基于
objc_msgSend
的方法调度的性能。尽管 Swift 类中的方法也是虚拟的,但当您没有使用 @objc
属性显式标记方法时,编译器能够使用更快的方法来分派方法 - 特别是当 Whole Module Optimization 打开时 ,甚至更多所以在 Swift 3 中,类默认不开放用于定义类型的模块之外的子类化。
除了避免使用 NSObject 之外,在编写 Swift 时,在很多情况下你还可以完全避免基于类的引用类型。例如,请查看上面链接的价值类型 WWDC 视频,或者例如作为介绍的此博文。简而言之,使用值类型可以获得良好的本地推理,通常可以避免动态内存分配和引用计数开销(尽管并非普遍如此 - 具有引用类型作为字段的结构是警告)。
您必须子类化的另一种情况
NSObject
是当您希望您的子类成为 KVO 的观察者时,即
addObserver(_ observer: NSObject, forKeyPath keyPath: String, options: NSKeyValueObservingOptions = [], context: UnsafeMutableRawPointer?)
要求观察者是一个
NSObject
(或者数组或集合)。
斯威夫特 4.1 更新
在 Swift 4.1 中,不推荐使用类来限制引用类型的协议一致性,而是使用 AnyObject。现在,我们应该使用 AnyObject 作为协议继承,以确保只有类类型才能符合给定的协议。
为什么使用 AnyObject?
我。限制引用类型(仅限类):通过从 AnyObject 继承,该协议只能被类类型采用,不包括结构体和枚举。当您需要类独有的功能(例如引用语义)时,这特别有用。
二.使用弱引用:创建委托时,经常使用弱引用来防止强引用循环。弱引用仅允许用于类类型,这使得 AnyObject 对于定义委托协议至关重要。 如果没有 AnyObject,则无法声明对协议类型的弱引用,因为弱引用仅适用于类
protocol MyProtocol: AnyObject {
func doSomething()
}
class MyClass: MyProtocol {
func doSomething() {
print("Doing something")
}
}
class AnotherClass {
weak var delegate: MyProtocol? // Works because MyProtocol inherits from AnyObject
}