前言#
kvo 全称是 key value observe。键值观察的意思,观察某个对象做出响应,由 NSKeyValueObserving 协议提供支持,NSObject 类继承了该协议,所以 NSObject 的子类都可使用该方法。
使用步骤#
- 注册一个监听(指定观察者,以及要观察的属性)
/*
options: 有4个值,分别是:
NSKeyValueObservingOptionOld 把更改之前的值提供给处理方法
NSKeyValueObservingOptionNew 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
*/
//注册一个监听器用于监听指定的key路径
[self.person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];- 实现一个协议方法(响应)
//当key路径对应的属性值发生改变时,监听器就会回调自身的监听方法,如下
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSKeyValueChangeKey,id> *)change
context:(void *)contex
}移除观察者,在 监听器消失的时候记着 delloc 监听器
[self removeObserver:self forKeyPath:@“age"];//注意点
注意点#
移除与添加成对出现,防止出现野指针。
kvo 使用场景#
- 数据保存实时性(例如 user)—kvc 也可触发kvo。
- 对象属性触发某个操作(滑动)
KVO 的实现原理#
如果原类为 Person,那么生成的派生类名为 NSKVONotifying_Person 每个类对象中都有一个 isa 指针指向当前类,当一个类对象的第一次被观察,那么 系统会偷偷将 isa 指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的 setter 方法。
键值观察通知依赖于 NSObject 的两个方法 willChangeValueForKey:didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
补充:KVO 的这套实现机制中苹果还偷偷重写了 class 方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类。
总结#
运用oc的runtime特性的isa-swizzling技术实现的,(修改对象的isa指向 重写setter方法来实现的监听机制。A对象注册观察者B后,A类在运行的时候生成一个中间子类c,C重写了 setter方法,子类setter方法调用父类的setter方法。调用父类的setter方法之前调用了willChangeValueForKey,之后调用了,didChangeValueForKey最后调用了observeValueForKeyPath。c也重写了class方法,作用是对外界隐藏以达到外界不知道这个类的存在。