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指针查找实例的类对象。
这里之所以使用runtime获取类对象而不使用消息发送机制,是因为class是通过消息发送查找到class方法,在class方法中返回的类对象,而class方法可能被重写。
通过上图我们可以看出,使用KVO监听的属性的isa指向的类对象已经不是Person了,而是一个继承自Person的一个新的类 NSKVONotifying_Person ,我们并没有创建过这个类,它是objc的runtime动态生成的。
NSKVONotifying_Person重写了父类的 setAge:
、 class
、 dealloc
方法,并且新增了一个 _isKVOA
方法。
NSKVONotifying_Person的setter方法
我们可以看出在为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
通过上面我们可以得知,KVO的实现主要是因为在setter方法中调用 _NSSetIntValueAndNotify
,而它调用 willChangeValueForKey
,然后调用父类的 setAge
方法,再调用 didChangeValueForKey
方法, didChangeValueForKey
告诉 observeValueForKeyPath
属性改变。所以我们可以通过实现will和did方法手动出发KVO。
成员变量会不会触发KVO
通过上面原理我们可以知道,KVO主要是通过重写setter方法实现的,而成员变量并不会实现setter方法,所以成员变量的改变并不会触发KVO。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网
猜你喜欢:- fasthttp原理简析
- Android DEPPLINK、APPLink 原理简析
- ObjC中Category的原理简析
- 某数加密的流程与原理简析
- CocosCreator 引擎资源加载与释放原理简析
- 简析OC中对象占用内存的原理
本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
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》 这本书的介绍吧!