美文网首页
4.KVO原理

4.KVO原理

作者: 平常心_kale | 来源:发表于2020-10-22 10:09 被阅读0次

KVO 是通过isa混写技术实现的,在运行时根据原始类创建一个中间类,这个中间类是这个原类的子类,并动态的修改当前对象的isa,指向中间类,并将class方法重写,返回原类的class。
所以苹果建议在开发中不应该依赖isa指针,而是通过class实例方法来获取对象类型。

一.举例实现

.这里新建一个Peson,继承NSObject,person有一个age属性。对这个对象的 age属性进行KVO

问题:

通过addObserver添加 注册观察者, self ->观察者 我, 关联一个观察者, 给Person添加一个观察者, p是否强引用self ?
答:KVO不能对观察者强引用,注意观察者生命周期,但p会调用observerValueForPath 方法

二.运行后查看变化

通过object_getClass 获取实例对象 的isa指向的类对象,
然后通过po 命令打印 发现kVO之前还是原来的Person对象,KVO之后就变成了NSKVONotifying_Person这个对象了,通过查看源码发现这个对象的结构有 isa,supperClass,_isKVOA,这些属性。

三.查看添加监听前后的方法的具体实现

设置监听之前:调用的是 MLPerson 里边的 setAge:方法
设置监听之后:调用的是新的子类里边的 setAge:方法,只不过 里边调用了 Foundation框架 里边的 _NSSetIntValueAndNofify方法

KVO后.png
四、窥探 _NSSetIntValueAndNofify 方法实现

_NSSetIntValueAndNotify的内部实现
1.先调用了 willChangeValueForKey:方法
2.接着调用 父类的 setAge:方法(也就是MLPerson里边的setAge方法,使age的值真正发生变化)
3.发生变化之后 会接着调用 didChangeValueForKey: 方法

在此方法内部,通知监听器 某个对象的 属性值 发生了变化 接着触发 KVO的监听方法 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context;
KVO本质.png
五、如果修改了 成员变量会不会触发KVO?

不会。因为没有调用 setter方法


不触发KVO.png
以上触发方式是自动触发,默认是自动触发的。

六、如何手动触发KVO

还有一个手动触发,(automatica 模式调整)主要是应用于开发中的一些场景。

所以手动触发,在willChangevalueforkey 和 didchangevalueforkey 中间 改变值,手动触发不管有没有属性的改变 只要调用 这两个方法就会被触发。

另外 KVO被触发后,一定是触发了这个对象的 set方法,或者KVC赋值,

手动触发KVO.png

七、iOS 默认不支持数组的KVO

但是iOS 默认不支持数组的KVO,kVO只对set方法会触发,但是对add不会触发。

对于一个普通可变数组,我们对这个数组KVO,直接监听当前的count或者lastObject 都会导致崩溃。

方法一:我们要把数组包装一层,新建一个类,这个类中申明一个可变数组,然后对这个类的数组属性KVO

_arrayModel = [ArrayModel new];

[_arrayModel addObserver:self forKeyPath:@"dataArray" options:NSKeyValueObservingOptionNew context:nil];

特别注意不能用 array add remove 要用
[[_arrayModel mutableArrayValueForKeyPath:@"dataArray"] addObject:XXX];

方法二:手动调用didChandgeValueForKey方法、
//要监听的数组,不可变数组也一样
@property (nonatomic, copy) NSMutableArray *array;

//另外在想要发出array变化的地方调用
[self willChangeValueForKey:@"array"];
//这边模拟元素内容变化,实际上调用了willChangeValueForKeydidChangeValueForKey方法,不管数组内容有没有变化都会告知监听者
[self..array addObject:@"piaojin"];
[self didChangeValueForKey:@"array"];

KVO 属性依赖 (属性中有个 dog 类对象,这个dog有个age 属性)
观察 keyPath dog.age 也是可以的

就要用到一个方法 keyPathForValueAffectingValueForKey

最后

而在这个整个过程中重写class方法目的就是不暴露出这个中间类。
因为当对象调用class方法时,会在自己的方法缓存列表,方法列表,父类缓存,父类方法
列表一直向上查找,因为class方法是NSObject中的方法,如果没有重写最终可能会返回这个中间类。
NSKVONotifying_Person,会给开发人带来疑惑。

相关文章

  • 4.KVO原理

    KVO 是通过isa混写技术实现的,在运行时根据原始类创建一个中间类,这个中间类是这个原类的子类,并动态的修改当前...

  • iOS开发-4.KVO

    1.什么是KVO? 2.未使用KVO监听的对象 3.使用了KVO监听的对象 4.查看_NSSet*AndNotif...

  • ios学习视频

    喜欢的hank老师的技术视频 1.runtime讲解 2.runloop视频讲解 3.数据结构 4.kvo 5.k...

  • 值得收藏的博客

    1.微信读书团队2.使用clang 编译 Objective-C的 .m文件3.获取系统日历的写入权限4.KVO实...

  • RAC 初学

    1.给按钮绑定方法 2.添加代理方法 3.接收通知 4.KVO MAP 映射的意思,就是创建一个订阅者的映射并且返...

  • 华与华方法(8)传播第一原理

    传播三大原理: 第一原理:刺激反射原理 第二原理:播传原理 第三原理:信号能量原理。 一、刺激反射原理 所有传播都...

  • 大数据相关

    hadoop原理 spark原理 kafka原理 数据仓库部分 Hadoop原理 MapReduce的原理默认根据...

  • js call apply instanceof 实现原理

    call原理 apply原理 instanceof原理

  • 《影响力》读后感

    全书主要围绕六大原理开展,分别是互惠原理,承诺和一致原理,社会认同原理,喜好原理,权威原理,以及稀缺原理。全文结构...

  • Today面试

    Runloop 底层原理Kvo 底层原理ARC 底层原理 如何实现GCD 底层原理Block 底层原理Aut...

网友评论

      本文标题:4.KVO原理

      本文链接:https://www.haomeiwen.com/subject/rxvhjhtx.html