我的个人项目 | 扫雷Elic 无尽天梯 | 梦见账本 |
---|---|---|
类型 | 游戏 | 财务 |
AppStore | Elic | Umemi |
KVO
在开发中还是经常使用的,但是有些隐秘的角落却经常被忽视,本文将对这些角落进行一些探究。
Important: In order to understand key-value observing, you must first understand key-value coding.
它影响通知中提供的更改字典的内容以及生成通知的方式。
更改之前的值
接收新值
您指示被观察对象使用选项 NSKeyValueObservingOptionInitial
发送立即更改通知(在 addObserver:forKeyPath:options:context:returns
之前)。您可以使用这个额外的一次性通知来获取初始值。
您可以通过包含选项 NSKeyValueObservingOptionPrior
指示被观察对象在属性更改之前发送通知(除了更改之后的通常通知之外)。
变更字典通过包含键 NSKeyValueChangeNotificationIsPriorKey
和包含 YES
的 NSNumber
值来表示预更改通知。
可以通过这些选项的按位枚举接收多种
[tool.ryuk addObserver:tool forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:NULL];
在平时使用时,我们一般就传个 NULL
但是他到底是做什么的有想过么?
addObserver:forKeyPath:options:context:
消息中的 Context
指针可以包含任意数据,这些数据将在相应的更改通知中传递回观察者。您可以指定 NULL
并完全依赖键路径字符串来确定更改通知的来源,但是这种方法可能会导致对象的父类由于不同原因也在观察相同的键路径时出现问题。
一种更安全、更可扩展的方法是使用 Context
来确保您收到的通知是发送给您的观察者而不是父类的。
类中唯一命名的静态变量的地址是一个很好的 Context
。在父类或子类中以类似方式选择的 Context
不太可能重叠。您可以为整个类选择一个 Context
,并依靠通知消息中的关键路径字符串来确定发生了什么变化。
或者,您可以为每个观察到的键路径创建一个不同的 Context
,这完全绕过了字符串比较,从而提高了通知解析的效率。
创建 Context
指针
static void *PersonAccountBalanceContext = &PersonAccountBalanceContext;
static void *PersonAccountInterestRateContext = &PersonAccountInterestRateContext;
注册观察者
- (void)registerAsObserverForAccount:(Account*)account {
[account addObserver:self
forKeyPath:@"balance"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:PersonAccountBalanceContext];
[account addObserver:self
forKeyPath:@"interestRate"
options:(NSKeyValueObservingOptionNew |
NSKeyValueObservingOptionOld)
context:PersonAccountInterestRateContext];
}
相对可变数组进行 KVO
很可能会写出这样的代码。但是明显是没用的。这就不得不提文章开始的那句官方提示 重要:为了能理解 KVO ,必须先理解 KVC。
访问集合属性 Accessing Collection Properties有提到,为了使可变集合内部的变化,能够被监听到需要调整一下 API
mutableArrayValueForKey:
and mutableArrayValueForKeyPath:
NSMutableArray
mutableSetValueForKey:
and mutableSetValueForKeyPath:
NSMutableSet
mutableOrderedSetValueForKey:
and mutableOrderedSetValueForKeyPath:
NSMutableOrderedSet
如果你写了一个库,不希望内部的一些属性被监听到。有没有办法阻止掉呢?
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key;
系统提供了上面的方法,默认是返回 YES
,即:所有属性都可以被监听。如果你不希望部分或者全部被监听可以返回 NO
。
没有触发变动的通知
name
的通知没有触发,books
的通知正常触发了。
虽然 automaticallyNotifiesObserversForKey
禁止了通知,但是手动触发后依旧可以正常监听到