核心原理
KVO是建立在KVC的基础上。只有在使用KVC准则访问访问器或成员变量的情况下,才可以监视属性的变化。
NSObject中提供了NSKeyValueObseving类别扩展。
KVO是通过isa-swizzling
技术实现的(这句话是整个KVO实现的重点)。在运行时根据原类创建一个中间类,这个中间类是原类的子类,并动态修改当前对象的isa指向中间类,中间类重写 setter 方法添加了通知代码,并且将class方法重写,返回原类的Class,所以调用object_getClass
函数后返回的是其真正的类。所以苹果建议在开发中不应该依赖isa指针,而是通过class实例方法来获取对象类型。
监听获取
NSKeyValueObservingOptionNew:change字典包括改变后的值
NSKeyValueObservingOptionOld:change字典包括改变前的值
NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知
NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)
手动触发与禁止
在setter中调用:
- (void)willChangeValueForKey:(NSString *)key;
- (void)didChangeValueForKey:(NSString *)key;
实现:
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key;
KVO与多线程
一个需要注意的地方是,KVO 行为是同步的,并且发生与所观察的值发生变化的同样的线程上,没有队列或者 Run-loop 的处理。手动或者自动调用-didChangeValueForKey:
会触发 KVO 通知。
所以,当我们试图从其他线程改变属性值的时候我们应当十分小心,除非能确定所有的观察者都用线程安全的方法处理 KVO 通知。通常来说,我们不推荐把 KVO 和多线程混起来。如果我们要用多个队列和线程,我们不应该在它们互相之间用 KVO。
KVO 是同步运行的这个特性非常强大,只要我们在单一线程上面运行(比如主队列 main queue),KVO 会保证下列两种情况的发生:
首先,如果我们调用一个支持 KVO 的 setter 方法,如下所示:
self.exchangeRate = 2.345;
KVO 能保证所有 exchangeRate 的观察者在 setter 方法返回前被通知到。
保证移除监听
removeObserver:forKeyPath:方法将KVO移除
参照
http://www.cocoachina.com/ios/20180319/22651.html
https://www.jianshu.com/p/b9f020a8b4c9
https://github.com/facebook/KVOController
网友评论