0、KVO 简介
KVO(NSKeyValueObserving)为键值观察,是一种非正式协议,它定义了一种机制,允许对象去监听其它对象的某个属性的修改。
我们可以监听一个对象的属性,包括简单属性,一对一的关系,和一对多的关系(监听一个集合或数组)。一对多关系的监听者会被告知集合变更的类型,以及哪些对象参与了变化。
1、KVO 和 runtime 有什么联系?
Objective-C 依托于强大的 runtime 机制来实现 KVO(具体见问题 2).
2、KVO 的底层实现原理是什么?
2.0 知识来源
摘自南峰子技术博客!!!
http://southpeak.github.io/2015/04/23/cocoa-foundation-nskeyvalueobserving/
2.1 底层原理
当我们第一次观察某个对象的属性时,runtime 会创建一个新的继承自这个对象的 class 的subclass。在这个新的 subclass 中,它会重写所有被观察的 key 的 setter,然后将 object 的 isa 指针指向新创建的 class(这个指针告诉 Objective-C 运行时某个 object 到底是什么类型的)。所以 object 神奇地变成了新的子类的实例。
KVO 底层原理2.2 代码示例
代码示例 测试结果从输出中可以看到,bankInstance2 监听 accountBalance 属性后,其实际上所属的类已经不是BankObject 了,而是继承自 BankObject 的 NSKVONotifying_BankObject 类。同时,NSKVONotifying_BankObject 类重写了 setAccountBalance 方法,这个方法将实现如何通知观察者们的操作。当改变 accountBalance 属性时,就会调用被重写的 setAccountBalance 方法,并通过这个方法来发送通知。
另外我们也可以看到 bankInstance2 对象的打印 [bankInstance2 class] 时,返回的仍然是BankObject。这是苹果故意而为之,他们不希望这个机制暴露在外面。所以除了重写相应的setter,所以动态生成的 NSKVONotifying_BankObject 类还重写了 class 方法,让它返回原先的类。
3、如何手动实现 KVO?
3.1 简介
手动控制通知提供了对 KVO 更精确控制,它可以控制通知如何以及何时被发送给观察者。采用这种方式可以减少不必要的通知,或者可以将多个修改组合到一个修改中。
实现手动通知的类必须重写 NSObject 中对 automaticallyNotifiesObserversForKey:方法的实现。这个方法是在 NSKeyValueObserving 协议中声明的,其声明如下:
手动通知需重写该方法假如我们希望 Observer 监听 Student 类的 name 属性时实现手动通知,我们需要在修改属性值前调用 willChangeValueForKey:,然后在修改属性值之后调用 didChangeValueForKey:方法。
3.2 定义一个被观察的对象Student
Student类有学号、姓名、书籍三个属性 重写 setter 方法,手动调用 willChange 与 didChange3.3 定义一个观察者类Observer
Observer.m 文件需实现 observeValueForKeyPath: ofObject: change: context:方法3.4 测试手动通知
3.4.1 测试代码
测试代码3.4.2 测试结果
测试结果我们可以看到只输出了一次,而不是两次。
参考文档:
网友评论