Key-value observing(简称KVO)是一种机制,它允许某个对象的属性发生变化时通知其它对象。
Key-value observing主要的好处是,它拥有框架级的支持,使用Key-value observing无需为项目导入其它代码。
不同于NSNotificationCenter的通知,KVO机制中没有负责发送通知的中心对象。当对象的属性发生变化时,该对象直接向所有它的观察者发送通知。
注册Key-Value Observing
为了正常接收到Key-Value Observing通知,必须遵循3个步骤:
- 被观察对象调用
addObserver:forKeyPath:options:context:方法添加观察者. - 观察对象(接收通知的一方)内部实现
observeValueForKeyPath:ofObject:change:context:方法用于接收通知. - 当观察者不想(或不能)接收通知时,使用
removeObserver:forKeyPath:方法注销。至少需要在观察者从内存释放之前调用该方法。
step1:注册为观察者
被观察对象调用addObserver:forKeyPath:options:context:方法添加观察者.
eg: 将self注册为观察者,监听account对象的balance和interestRate属性。
|
|
Options
Options参数用于指定接收什么类型的通知、通知需要携带什么内容。
NSKeyValueObservingOptions:
- NSKeyValueObservingOptionNew: 指明通知中应该包含 属性的新值。
- NSKeyValueObservingOptionOld: 指明通知中应该包含 属性的旧值。
- NSKeyValueObservingOptionInitial: 一旦指明此option,被观测对象会立刻发送通知(在
addObserver:forKeyPath:options:context:return之前)。通常用于获取属性的初始值。 - NSKeyValueObservingOptionPrior: 指明在属性每次变化前和变化后都发送通知。并且通知中的change dictionary 总是包含
NSKeyValueChangeNotificationIsPriorKey条目,值为NSNumber封装的bool类型,等于@YES表明接收到的是变化前的通知,等于@NO表明接收到的是变化后的通知。
Context
Context参数是一个指针,会传回给观察者的回调方法,作为唯一标识使用。大多数情况下,在回调方法内使用key path字符串就可以区分不同的通知,所以Context参数通常会设置为nil或者NULL。
step2:接收通知
观察对象必须实现observeValueForKeyPath:ofObject:change:context:方法。
当被观察属性的值发生变化时,观察对象的observeValueForKeyPath:ofObject:change:context:方法会被回调。
|
|
在本示例中,通过key path足以判断是哪个对象的属性发生了变化,所以可以这样:
step3:移除观察者
被观察对象调用removeObserver:forKeyPath:context:方法移除观察对象。
|
|
常见问题
报错:libc++abi.dylib: terminate_handler unexpectedly threw an exception
发生于被观察者向一个不存在的对象发送通知,所以,一定不要忘记在合适的时候进行 removeObserver 操作,至少在观察者内存被释放之前。
此错误最常发生于,ViewController pop 后或 dismiss 后。
KVO在swift中不管用?
对于自定义的 class,首先需要确保该 class 是 NSObject 的子类;
其次,需要使用dynamy关键字修饰被察者属性;
比如,我们自定义Person类,希望它的birthday属性可以被观察:
|
|
适合在ViewController addObserver/removeObserver 的时机?
个人推荐通常情况下在 viewDidAppear 中 addObserver: 此时视图都加载完毕,并显示出来。
在 viewDidDisappear 中 removeObserver:此时视图已经消失,并且视图对象可能已经销毁。
这只是通常情况,你需要根据自己的需求选择最合适的时机。
另一个建议是,不要在 viewWillAppear、viewWillAppear 中 addObserver、removeObserver:
因为一个 ViewController 作为 subcontroller 时,其 viewWillAppear、viewWillAppear并不会在每次视图显示、消失时被调用。
参考链接:
Introduction to Key-Value Observing Programming Guide
Registering for Key-Value Observing
Understanding Key-Value Observing and Coding