键值观察KVO(Key-Value Observing)是一种允许通知对象--其他对象的制定属性已经作出更改--的机制。主要用到NSKeyValueObserving类
要使用KVO,必须确保所观察的对象符合KVO标准,通常情况下,如果所创建的对象继承自NSObject并且以常规方式创建属性,那么该对象及其属性将自动符合KVO标准。
使用步骤
1、注册观察对象
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
-
observer:观察者,观察者通过上面方法发送消息向观察者对象进行注册,并将自身作为参数传递给被观察对象
-
keyPath:被观察对象的属性路径
-
options:观察选项,是一个枚举类型NSKeyValueObservingOptions
- NSKeyValueObservingOptionNew:接收到的数据字典中包含NSKeyValueChangeNewKey键,对应的值为属性发生改变后的新值
- NSKeyValueObservingOptionOld:接收到的数据字典中包含NSKeyValueObservingOptionOld键,对应的值为属性发生改变前的旧值
- NSKeyValueObservingOptionInitial:会在注册的时候使观察方法调用一次
- NSKeyValueObservingOptionPrior:会在观察属性值改变的前后均调用一次。其中在变化前调用的一次时NSKeyValueObservingOptionNew对应的值为NULL,NSKeyValueObservingOptionOld对应的值为变化前的值
-
context:相关联的上下文,该参数可以设置为NULL并完全依赖关键路径字符串(keyPath)来确定更改通知的来源,但是如果该类的父类也观察相同keyPath,那么这里设为NULL可能会出问题。更安全和可扩展的方法是使用上下文来确保收到的通知是正确的观察者
官方文档示例:使用静态变量的地址作为上下文内容
static void * PersonAccountBalanceContext =&PersonAccountBalanceContext; static void * PersonAccountInterestRateContext =&PersonAccountInterestRateContext;
2、实现检测的方法
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSKeyValueChangeKey, id> *)change context:(nullable void *)context;
当被观察对象属性值发生变化时,观察者会收到一条消息。观察者必须实现这个方法,在该方法中可以通过keyPath
或者context
去判断数据来源,若要取出change
字典里的值要使用下面枚举定义的key
-
NSKeyValueChangeKindKey:属性改变的类型,
change
中会永远包含的键,对应的值为NSUInteger类型,系统定义了一个枚举类型与之对应。- NSKeyValueChangeSetting = 1 由于设置新值造成的改变
- NSKeyValueChangeInsertion = 2 由于在集合中插入元素造成的改变
- NSKeyValueChangeRemoval = 3 由于在集合中移除元素造成的改变
- NSKeyValueChangeReplacement = 4 由于在集合中发生替换元素造成的改变
-
NSKeyValueChangeNewKey:只有在注册观察者的时候在
optional
参数中加入NSKeyValueObservingOptionNew
时才会被change
参数包括,获取改变后的新值 -
NSKeyValueChangeOldKey:只有在注册观察者的时候在
optional
参数中加入NSKeyValueObservingOptionOld
时才会被change
参数包括,获取改变前的旧值 -
NSKeyValueChangeIndexesKey:只有当被观察对象属性是集合的情况下,这个键值才会被
change
参数包含,获取集合中改变的元素的index,NSIndexSet类型 -
NSKeyValueChangeNotificationIsPriorKey:只有当注册观察者的时候在
optional
参数中加入NSKeyValueObservingOptionPrior
时,这个键值才会被change
参数包含,NSNumber类型
3、移除观察者
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context / - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
观察者在释放时不能主动释放自己,被观察对象还可以继续发送消息给观察者,但是如果观察者已经释放掉,这个时候会触发内存访问异常,所以一定要在观察者被释放之前移除观察者。常见的模式是在viewDidLoad
注册为观察者,在dealloc
注销观察者。
网友评论