上面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。