Jerry Lee

stay hungry,stay young.

Welcome to my world.


Kvo的本质


KVO的全称是Key -Value Observing,即“键值监听”,可用于监听某个对象属性值的改变


代码实现

WX20190403-152226.png-209.2kB

结果输出 WX20190403-153047.png-11.3kB

可以看到我们只监听了person1属性值改变,所以只输出person1的改变。那问题来了,我们给person1,person2都改变了age属性的值,本质都是调用了LGPerson类中setAge这个方法,那么为什么person1会走到oberveValueForKeyPath这个方法,person2不会呢? KVO底层实现分析 ——— 我们断点打印一下person1和person2的isa,看一下他们实例对象isa指向的类对象是什么?

WX20190403-154305.png-12.7kB

person1的isa指针打印出的是NSKVONotifying_LGPerson,person2的isa指针打印出的是LGPerson 如果不监听person1的属性,我们看一下person1的isa指针

WX20190403-161900.png-6.4kB person1和person2都是实例对象,所以person1和person2的isa指针指向的都是类对象。 通过对比我们发现两者isa指针指向的对象发生了变化,现在我们再做深一步的研究,添加监听之后两者调用的setAge方法有没有变化呢

WX20190403-162858.png-17kB

WX20190403-162931.png-17.6kB 果然和我们猜想的一样,监听之后调用方法变成了_NSSetIntValueAndNotify 如果定义的属性是类型是double,则调用的是_NSSetDoubleValueAndNotify(),那么我们可以推测Foundation框架中有许多此类型的函数比如_NSSetBoolValueAndNotify,_NSSetCharValueAndNotify,_NSSetFloatValueAndNotify,通过属性的不同类型调用不同的函数。


NSKVONotifying_LGPerson内部结构解析

WX20190403-164346.png-88.4kB 打印结果: WX20190403-164319.png-11.5kB 通过上述代码我们发现NSKVONotifying_LGPerson中有4个对象方法。分别为setAge: class dealloc _isKVOA

验证didChangeValueForKey:内部会调用observer的observeValueForKeyPath:ofObject:change:context:方法

WX20190403-165304.png-73.9kB 打印结果: WX20190403-165527.png-37.2kB 通过打印内容可以看到,确实在didChangeValueForKey方法内部已经调用了observer的observeValueForKeyPath:ofObject:change:context:方法。

最近的文章

深入理解runloop

RunLoop简介运行循环,在程序运行过程中循环做一些事情,如果没有Runloop程序执行完毕就会立即退出,如果有Runloop程序就会一直运行,并且时时刻刻在等待用户的输入操作。RunLoop可以在需要的时候自己跑起来运行,在没有操作的试试就停下来休息。充分节省CPU资源,提高程序性能。RunLoop基本作用1.保持程序持续运行 程序一启动就会开一个主线程,主线程一开起来就会跑一个主线程对应的RunLoop,RunLoop保证主线程不会被销毁,也就保证了程序的持续运行;2.处理App中的...…

继续阅读
更早的文章

多线程gcd(一)

(一)各种队列的执行效果1.常见的多线程方案2.同步和异步的主要影响:能不能开启新的线程同步:在当前的线程中执行任务,不具备开启新线程的能力异步:在新的线程中开启任务,具备开启新线程的能力3.并发和串行的主要影响:任务的执行方式并发:多个任务并发(同时)执行串行:一个任务执行完毕之后,再执行下个任务队列的类型包括:并发队列,串行队列,主队列(也是一个串行队列)决定了任务的执行方式(并发,串行)(二)常见的死锁案例使用sync函数往当前串行队列中添加任务,会卡住当前的串行队列(产生死锁)1....…

继续阅读