键值观察(Key-value observing)是一种允许通知对象--其他对象的指定属性已经做出更改--的机制。相关文档。其主要使用到NSKeyValueObserving.h
类。
要使用KVO,必须确保所观察的对象符合KVO标准,通常情况下,如果创建的对象继承自NSObject并且以常规方式创建属性,那么该对象及其属性将自动符合KVO标准。
常用使用方式步骤:
-
注册观察对象:
- (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
对应改变前的值。多用在开发者手动创建支持的KVO中。
-
-
- 参数
context
为相关联的上下文:该参数可以指定为NULL并完全依赖关键路径字符串(keyPath)来确定更改通知的来源,但是如果该类的父类也观察相同keyPath,那么这里设为NULL可能会出现问题。更安全和更可扩展的方法是使用上下文来确保收到的通知是正确的观察者。
官方文档示例:使用静态变量的地址作为上下文内容
static void * PersonAccountBalanceContext =&PersonAccountBalanceContext;
static void * PersonAccountInterestRateContext =&PersonAccountInterestRateContext;
-
实现监测的方法:
- (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中永远包含的的键,对应的value为NSUInteger类型,系统定义了一个枚举类型与之对应。-
NSKeyValueChangeSetting = 1
: 由于设置新值造成的改变; -
NSKeyValueChangeInsertion = 2
:由于在集合中插入新元素造成的改变; -
NSKeyValueChangeRemoval = 3
: 由于在集合中移除元素造成的改变; -
NSKeyValueChangeReplacement = 4
: 由于在集合中发生替换元素造成的改变。
-
-
NSKeyValueChangeNewKey;
只有当addObserver:
的时候在optional
参数中加入NSKeyValueObservingOptionNew
,这个键值对才会被change参数包含。获取改变后的新值; -
NSKeyValueChangeOldKey;
只有当addObserver:
的时候在optional
参数中加入NSKeyValueObservingOptionOld
,这个键值对才会被change参数包含。获取改变前的旧值; -
NSKeyValueChangeIndexesKey;
只有被观察对象是集合的情况下,这个键值对才会被change参数包含。获取在集合中改变的元素的index,NSIndexSet类型; -
NSKeyValueChangeNotificationIsPriorKey;
只有当addObserver:
的时候在optional
参数中加入NSKeyValueObservingOptionPrior
,这个键值对才会被change参数包含。NSNumber类型。
-
-
移除观察者:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context
/- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
-
观察者在释放时不会自动删除自己。被观察的对象继续发送通知,但是发送给已经释放的对象会触发内存访问异常。所以应该确保观察者在内存释放之前将其移除。
-
常见的的模式是在观察者初始化期间(viewDidLoad)注册为观察者,在释放期间(dealloc)注销观察者,确保正确配对和有序的添加和移除消息。
-
网友评论