OC基础知识点之-KVO(键值观察)-下

707 阅读3分钟

系列文章:OC底层原理系列OC基础知识系列

上面KVO介绍结尾我们说要进行自定义KVO,这篇我们来说下自定义KVO

自定义观察者KVO

整体思想

自定义KVO其实和系统是一样的,就是在系统基础上进行优化,我们这里采用的是函数式编程思想来自定义KVO。主要分为以下两个方法

  • 1.将注册和响应过程合并,通过函数式编程思想即block的方式进行响应
  • 2.去掉系统KVO的手动销毁机制,改为自动销毁。 具体实现分为以下三步: 1.注册观察者
// block返回内容(仿照系统返回)
typedef void(^LJKVOBlock)(id observer,NSString *keyPath,id oldValue,id newValue);

// 注册方法
- (void)lj_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath block:(LJKVOBlock)block;

2.KVO响应

这部分主要通过重写setter方法,在中间类的setter方法中,通过block方式传递给外界进行响应。

3.移除

- (void)lj_removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

下面我们创建一个NSObject分类LJKVO,开始我们的实现过程:

注册观察者

在实现注册方法中,需要以下过程

  • 1.判断当前观察者是否存在setter方法,目的是为了防止实例变量进入
  • 2.动态生成中间类,将需要重写的class方法添加到中间类中
  • 3.isa指向由原类指向中间类
  • 4.保存传入的信息,这里用的是LJInfo的模型 先看下LJInfo模型 通过JLInfo模型,将信息保存起来(我们这里用的是数组,也可以用字典) 此时我们已经将外界穿过来的信息存储起来,并且将isa指针指向了中间类,注册完成。

KVO的相应

我们知道在系统方法里,KVO的响应是通过中间类的setter方法,此时我们需要给中间动态添加setter方法,目的就是为了在setter方法中向父类发送消息,通知属性值发生变化。

  • 5.将setter方法重写添加到子类中(主要是在注册观察者方法中添加)
  • 6.通过将系统的objc_msgSendSuper强制类型转换自定义的消息发送cjl_msgSendSuper
  • 7.通知观察者去响应:获取信息,通过block传递

移除观察者

为了避免在外界不断的调用removeObserver方法,在自定义KVO中实现自动移除观察者

  • 8.实现lj_removeObserver:forKeyPath:方法,这个方法主要是清空数组,将isa指针改回原来的类
  • 9.在子类中重写dealloc方法,当子类销毁时,会自动调用dealloc方法(在动态生成子类的方法中添加) 其原理主要是:Person发送消息释放即dealloc了,就会自动走到重写的lj_dealloc方法中(原因是因为person对象的isa指向变了,指向中间类,但是实例对象的地址是不变的,所以子类的释放,相当于释放了外界的person,而重写的lj_dealloc相当于是重写了Person的dealloc方法,所以会走到lj_dealloc方法中),达到自动移除观察者的目的

总结

上面写的是大致过程,其中很多地方值得优化,可以看下facebook的KVO框架KVOController。 上面写的具体代码地址:自定义KVO