iOS 底层探索篇 —— KVO 底层原理(下)
1. 自定义KVO
创建一个NSObject分类,并添加三个方法,lg_addObserver,lg_observeValueForKeyPath和lg_removeObserver。

1.1 lg_addObserver
接下来就是方法的实现。那么对于lg_addObserver,实现的步骤大致如下:
- 验证是否存在setter方法 : 不让成员变量进来
- 动态生成子类
- isa的指向 : LGKVONotifying_LGPerson
- 保存观察者信息,setter方法会使用到这些信息
实现代码如下:
总体流程:

- 验证是否存在setter方法 : 不让成员变量进来

- 动态生成子类
动态生成子类分以下几个步骤
- 防止重复创建生成新类
- 申请类
- 添加class方法
- 添加setter
- 注册类
实现如下:

这里需要展示父类也不是动态子类,所以重写class方法,返回动态子类的父类。

这里的是获取setter方法的名称的实现,也就是将getter的第一个字母变为大写,然后在前面插入set。

setter则是需要调用父类的setter设置新值,然后取出观察者,根据设置的option来对change进行处理,然后发送通知,也就是调用lg_observeValueForKeyPath方法。

注意这里的observer要是weak属性,否则会有循环引用的问题。

1.2 lg_removeObserver
lg_removeObserver实现的步骤大致如下:
- 将储存的关于observer的信息移除
- 将isa重新指回原来的类
实现代码如下:

2. 自定义函数式KVO
lg_addObserver 和 lg_observeValueForKeyPath的话,那么就将逻辑代码和业务代码分开了,能不能用函数式编程思想,将他们放在一起呢?
实现一下。
先为KVO分类添加一个block,并且在addObserver的函数里面添加上这个block。

在保存信息的时候,将block也保存起来。

然后将原来的调用observeValueForket的地方改为调用block。

然后,外界的调用就变成了这样。

3. KVO自动销毁机制
KVO每次都需要手动去调用lg_removeObserver释放,那么能不能做到自动释放呢?
实现一下。
尝试在LGKVO分类里面重写dealloc方法,但是如果这样做的话,就会把所有的东西进行覆盖。
之前学过方法交换,那么是否可以在load的时候,把dealloc拦截下来,然后来到自己的实现里面。但是这样的话,那么所有的dealloc方法都会进行交换,明显不合理。
那么如果在进入KVO的时候进行交换,那么就会有交换多次的问题,还会对原始的dealloc方法有影响。
这里为实现KVO的动态子类里面添加dealloc方法,这样就相当于重写了,然后在实现里面将isa重新指回就可以了。


但是这样做还是不合理的,如果父类的实现里有太多的逻辑的话,那么应该怎么办呢?
4. FBKVOController
FBKVOController是Facebook开源的一个基于系统KVO实现的框架,其使用了函数式编程,可以一行代码实现系统KVO的三个步骤,可以同时对一个对象的多个属性进行监听,线程安全并且可以自动移除观察者。FBKVOController使用了中介者模式,通过创建一个FBKVOController的实例,并将所有监听、回调和释放的工作交过这个实例去完成。
那么FBKVOController是怎么实现自动remove的呢?
在VC中,FBKVOController的实例是VC的一个属性,当VC释放的时候,那么实例作为属性也会进行dealloc。
所以FBKVOController在dealloc里面调用了unobserveAll来进行观察者的释放。

实际调用_unobserveAll。

用_FBKVOSharedController单例调用unobserve来移除所有的观察者。

移除info后再调用removeObserver移除观察者。

本文深入探讨iOS中的自定义KVO实现,包括lg_addObserver与lg_removeObserver方法,以及如何采用函数式编程风格和FBKVOController进行优化。还涉及KVO的自动销毁机制和FBKVOController的自动移除观察者原理。
&spm=1001.2101.3001.5002&articleId=119271993&d=1&t=3&u=2a7e99081d8b4132afc46932955f877a)
1万+

被折叠的 条评论
为什么被折叠?



