OC对象 – KVO

💡 原文中文,约4400字,阅读约需11分钟。
📝

内容提要

OC对象-KVO是用来监听特定值改变的机制。文章介绍了KVO的基本运用和底层实现。通过代码示例和运行结果,说明了增加KVO监听的目标和未增加的目标的差异。底层实现中,通过动态生成子类和改变isa指向来实现KVO。文章还介绍了NSSetXXXValueAndNotify方法的伪代码和NSKVONotifying_ClassName类的其他方法。最后,提到了手动触发KVO监听的方法。

🔎

延伸解读

KVO 如何做到只监听特定对象

文章通过 person1 和 person2 的对比说明:只有添加了 KVO 监听的对象,其 setAge 方法才会被替换为 _NSSetIntValueAndNotify。这是因为 KVO 利用 Runtime 动态生成 NSKVONotifying_ZSXPerson 子类,并将被监听对象的 isa 指向该子类。未监听对象的 isa 仍指向原类,因此赋值不会触发监听回调。

动态子类对开发者透明

NSKVONotifying_ZSXPerson 重写了 class 方法,使其返回原类 ZSXPerson。这样开发者调用 [person1 class] 时不会看到内部生成的子类,避免困惑。此外,该子类还实现了 dealloc 和 _isKVOA 等方法,用于 KVO 的收尾和标识。

手动触发 KVO 的条件

直接通过下划线访问成员变量赋值不会触发 KVO,因为 KVO 重写的是 setter 方法。若想手动触发,必须依次调用 willChangeValueForKey: 和 didChangeValueForKey:。didChangeValueForKey: 内部会检查之前是否调用了 willChangeValueForKey:,只有成对调用才会通知监听器。

❓

Q&A

KVO是什么?

KVO是键值观察机制,用于监听特定值的改变。

如何在iOS项目中实现KVO?

在iOS项目中,可以通过创建类并实现addObserver方法来监听属性变化。

KVO监听的对象和未监听的对象有什么区别?

增加KVO监听后,setAge方法的实现地址会改变,而未增加监听的对象方法地址不变。

KVO的底层实现是怎样的?

KVO通过动态生成子类和改变isa指向来实现,监听对象的isa指向NSKVONotifying_ClassName。

如何手动触发KVO监听?

手动触发KVO需要调用willChangeValueForKey和didChangeValueForKey方法。

KVO监听的实现过程中,_NSSetXXXValueAndNotify方法的作用是什么?

_NSSetXXXValueAndNotify方法在调用setAge时,会执行willChangeValueForKey和didChangeValueForKey。

➡️

继续阅读