ObjC中KVO原理简析

栏目: Objective-C · 发布时间: 6年前

内容简介:通常我们通过显然实现这个功能的基础是属性值得改变,而属性值得改变需要调用setter方法。可是即使setter方法是我们重写的,并且在其实现中并没有编写关于监听属性改变通知监听的代码,KVO依然可以起作用。这是为什么呢?我们都知道一个类的实例方法存在于其类对象中,当一个类的实例向实例方法发送调用消息时候,会通过类实例的isa指针去其类对象中找到其对应的实例方法执行。setter方法就存在于类对象中。

通常我们通过 addObserver:forKeyPath:options:context 来监听某个实例的某个属性变化。当该属性的值发生变化的时候会通过 - (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context 通知我们。

显然实现这个功能的基础是属性值得改变,而属性值得改变需要调用setter方法。可是即使setter方法是我们重写的,并且在其实现中并没有编写关于监听属性改变通知监听的代码,KVO依然可以起作用。这是为什么呢?

KVO实现原理

我们都知道一个类的实例方法存在于其类对象中,当一个类的实例向实例方法发送调用消息时候,会通过类实例的isa指针去其类对象中找到其对应的实例方法执行。setter方法就存在于类对象中。

新的类对象

我们通过runtime的 object_getClass() 直接利用实例对象的isa指针查找实例的类对象。

ObjC中KVO原理简析

这里之所以使用runtime获取类对象而不使用消息发送机制,是因为class是通过消息发送查找到class方法,在class方法中返回的类对象,而class方法可能被重写。

通过上图我们可以看出,使用KVO监听的属性的isa指向的类对象已经不是Person了,而是一个继承自Person的一个新的类 NSKVONotifying_Person ,我们并没有创建过这个类,它是objc的runtime动态生成的。

ObjC中KVO原理简析

NSKVONotifying_Person重写了父类的 setAge:classdealloc 方法,并且新增了一个 _isKVOA 方法。

NSKVONotifying_Person的setter方法

ObjC中KVO原理简析

我们可以看出在为person实例添加observer之前和之后的 setAge: 方法的实现发生了变化,之前是直接调用类对象中存储的实例方法,添加之后调用了Foundation框架中 _NSSetIntValueAndNotify 函数。

之所以是_NSSet*IntValue* AndNotify是因为age属性我们定义的是int类型,若是其他类型则会相应更改

_NSSetIntValueAndNotify 方法中,会调用 willChangeValueForKey ,然后调用父类的 setAge 方法,再调用 didChangeValueForKey 方法。在 didChangeValueForKey 中通知属性改变,从而使得 observeValueForKeyPath 得到消息。

NSKVONotifying_Person的class方法

在我们获取person实例的类对象的时候,我们发现使用runtime的 object_getClass 和使用消息发送机制 [_person class] 得到的结果不一样,这是因为NSKVONotifying_Person重写了class方法的实现,在实现中调用了 [super class] ,而NSKVONotifying_Person又是Person的子类,所以获取到的Person。

NSKVONotifying_Person的dealloc方法

由于runtime在实例对象添加了KVO之后动态创建了类和一些对象,所以可能会在dealloc中回收这些资源。

NSKVONotifying_Person的_isKVOA方法

_isKVOA 应该是会返回一个BOOL类型的值,表示是否使用了KVO。

手动触发KVO

ObjC中KVO原理简析

通过上面我们可以得知,KVO的实现主要是因为在setter方法中调用 _NSSetIntValueAndNotify ,而它调用 willChangeValueForKey ,然后调用父类的 setAge 方法,再调用 didChangeValueForKey 方法, didChangeValueForKey 告诉 observeValueForKeyPath 属性改变。所以我们可以通过实现will和did方法手动出发KVO。

成员变量会不会触发KVO

通过上面原理我们可以知道,KVO主要是通过重写setter方法实现的,而成员变量并不会实现setter方法,所以成员变量的改变并不会触发KVO。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Learn Python the Hard Way

Learn Python the Hard Way

Zed A. Shaw / Addison-Wesley Professional / 2013-10-11 / USD 39.99

Master Python and become a programmer-even if you never thought you could! This breakthrough book and CD can help practically anyone get started in programming. It's called "The Hard Way," but it's re......一起来看看 《Learn Python the Hard Way》 这本书的介绍吧!

HTML 压缩/解压工具
HTML 压缩/解压工具

在线压缩/解压 HTML 代码

URL 编码/解码
URL 编码/解码

URL 编码/解码

SHA 加密
SHA 加密

SHA 加密工具