21.KVO几个被忽视的细节
前言
Important: In order to understand key-value observing, you must first understand key-value coding.
上面是 KVO 官方文档中的一句重要提醒:重要:为了能理解 KVO ,必须先理解 KVC。
一、 Options
它影响通知中提供的更改字典的内容以及生成通知的方式。
NSKeyValueObservingOptionOld
更改之前的值
NSKeyValueObservingOptionNew
接收新值
您可以通过这些选项的按位 OR 接收旧值和新值。
NSKeyValueObservingOptionInitial
您指示被观察对象使用选项 NSKeyValueObservingOptionInitial
发送立即更改通知(在 addObserver:forKeyPath:options:context:returns
之前)。您可以使用这个额外的一次性通知来获取初始值。
NSKeyValueObservingOptionPrior
您可以通过包含选项 NSKeyValueObservingOptionPrior
指示被观察对象在属性更改之前发送通知(除了更改之后的通常通知之外)。
变更字典通过包含键 NSKeyValueChangeNotificationIsPriorKey
和包含 YES
的 NSNumber
值来表示预更改通知。
二、 Context
在平时使用时,我们一般就传个 NULL
但是他到底是做什么的有想过么?
addObserver:forKeyPath:options:context:
消息中的 Context
指针可以包含任意数据,这些数据将在相应的更改通知中传递回观察者。您可以指定 NULL
并完全依赖键路径字符串来确定更改通知的来源,但是这种方法可能会导致对象的父类由于不同原因也在观察相同的键路径时出现问题。
一种更安全、更可扩展的方法是使用 Context
来确保您收到的通知是发送给您的观察者而不是父类的。
类中唯一命名的静态变量的地址是一个很好的 Context
。在父类或子类中以类似方式选择的 Context
不太可能重叠。您可以为整个类选择一个 Context
,并依靠通知消息中的关键路径字符串来确定发生了什么变化。
或者,您可以为每个观察到的键路径创建一个不同的 Context
,这完全绕过了字符串比较,从而提高了通知解析的效率。
创建 Context
指针
注册观察者
三、 对可变数组的观察
相对可变数组进行 KVO
很可能会写出这样的代码。但是明显是没用的。这就不得不提文章开始的那句官方提示 重要:为了能理解 KVO ,必须先理解 KVC。
访问集合属性 Accessing Collection Properties
为了使可变集合内部的变化,能够被监听到需要调整一下 API
mutableArrayValueForKey:
andmutableArrayValueForKeyPath:
return
NSMutableArray
mutableSetValueForKey:
andmutableSetValueForKeyPath:
return
NSMutableSet
mutableOrderedSetValueForKey:
andmutableOrderedSetValueForKeyPath:
return
NSMutableOrderedSet
四、 KVO 开关控制
如果你写了一个库,不希望内部的一些属性被监听到。有没有办法阻止掉呢?
系统提供了上面的方法,默认是返回 YES
,即:所有属性都可以被监听。如果你不希望部分或者全部被监听可以返回 NO
。
4.1 全部禁止
没有触发变动的通知
4.2 部分禁止
name
的通知没有触发,books
的通知正常触发了。
4.3 禁止后手动发送通知
虽然 automaticallyNotifiesObserversForKey
禁止了通知,但是手动触发后依旧可以正常监听到
参考
Last updated