iOS 底层探索篇 —— KVO 底层原理(下)

326 阅读3分钟

这是我参与8月更文挑战的第20天,活动详情查看:8月更文挑战

1. 自定义KVO

创建一个NSObject分类,并添加三个方法,lg_addObserver,lg_observeValueForKeyPath和lg_removeObserver。

在这里插入图片描述

1.1 lg_addObserver

接下来就是方法的实现。那么对于lg_addObserver,实现的步骤大致如下:

  1. 验证是否存在setter方法 : 不让成员变量进来
  2. 动态生成子类
  3. isa的指向 : LGKVONotifying_LGPerson
  4. 保存观察者信息,setter方法会使用到这些信息

实现代码如下: 总体流程:

在这里插入图片描述

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

在这里插入图片描述

  1. 动态生成子类 动态生成子类分以下几个步骤
  1. 防止重复创建生成新类
  2. 申请类
  3. 添加class方法
  4. 添加setter
  5. 注册类

实现如下:

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

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

在这里插入图片描述

1.2 lg_removeObserver

lg_removeObserver实现的步骤大致如下:

  1. 将储存的关于observer的信息移除
  2. 将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移除观察者。

在这里插入图片描述