九层之台,起于累土
Apple 用什么方式实现对一个对象的的 KVO ?
官方文档:
Key-Value Observing Implementation Details
Automatic key-value observing is implemented using a technique called isa-swizzling.
The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.
When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.
You should never rely on the isa pointer to determine class membership. Instead, you should use theclassmethod to determine the class of an object instance.
翻译:
键值观察实现细节:
自动键值观察使用一种叫做 isa-swizzling 的技术来实现的。
通过 isa 指针的名字可以看出,只想对象类别的指针维护了一个分发表。这个分发表包括了指向了这个类的方法的的指针,包括了志向类实现的指针,以及其他数据。
当一个观察者被注册观察某一对象的属性时,被观察者的 isa 指针发生了修改,它指向了一个中间类而不是被观察者的真实的类。这就造成了被观察者的类的 isa 指针不能准确的反映出这个实例(对象)的真实的 类别(Class)。
你永远不能通过 isa 指针来判断一个类的关系。而是通过实例(对象)的 class 方法来判断来判断这个实例的类别。
(仅供参考,如有错误,请予以指正)
⚠️ 以下内容非原创,写在这儿仅用于学习,出处为 iOS面试题集锦(附答案)- ChenYilong
从 Apple 的官方文档可以看出: Apple 并不希望过多暴露 KVO 的实现细节。不过可以通过 runtime 提供的方法来进行深入了解:
当观察一个对象时,一个新的类会被动态创建。这个被动态创建的新类是继承自该对象原有的类,并重写了被观察属性的 setter 方法。重写的 setter 方法会负责在调用原 setter 方法之前和之后,通知所有观察对象值得更改。最后通过 isa 混写 (isa-swizzling [ˈswizəl] )把这个对象的 isa 指针指向这个新创建的子类,对象就神奇的变成了新创建的子类的实例。
详细解释:
键值观察通知依赖于 NSObject 的两个方法:willChangeValueForKey: 和 didChangeValueForKey: 。在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就会记录就的值,而改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。可以手动实现这些调用,但很少有人这么做。一般我们只在希望能控制回调的调用时机时才会这么做。大部分情况下,改变通知会自动调用。
具体研究过程:KVO 实现原理