键-值观察者(key - value observing)是指当指定的对象的属性被修改时,允许对象接收通知的机制。
总的来说,也就是告诉一个对象,“我想要观察你的fido属性,如果它发生了变化,就通知我。当setFido: 方法被调用的时候,被观察的对象会发送消息告诉你,我的fido属性有一个新值了。”讨论KVO和讨论NSNotificationCenter时使用的语言很相似,二者底层实现原理很相似。
观察、回调
- 添加观察
- 无论lastTime何时发生变化,都要通知我它改变的新值以及改变之前的旧值
[被观察者 addObserver: 观察者
forKeyPath: @"被观察者的某一属性"
options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context: nil];
实现被观察属性发生变化时的回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)cahnge
context:(void *)context {
NSString *oldValue = [change objectForKey:NSKeyValueChangeOldKey];
NSString *newValue = [change objectForKey:NSKeyValueChangeNewKey];
}
- 在KVO中使用context
注意: 当在代码中将某个对象注册为观察者时,你需要传递指针为context。当接收变化的通知时,context会随通知一起发送。context可以用来回答:“这真的是我需要的通知吗?”例:
static int contextForKVO;
[被观察者 addObserver: self
forKeyPath: @"fido"
options:0
context: &contextForKVO];
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)cahnge
context:(void *)context {
// 这是不是我的?
if (context != &contextForKVO) {
// 将它传递给父类
[super observerValueForKeyPath:keyPath];
} else {
// 处理变化
}
}
- 显式触发通知
如果使用存取方法来设置属性,那么系统就会自动通知观察者。但由于某种原因,你选择不适用存取方法呢?这时可以通过willChangeValueForKey:和didChangeValueKey:方法通知系统木某个属性的值即将/已经发生变化。
NSDate *now = [NSDate date];
[self willChangeValueForKey:@"lastTime"];
_lastTime = now;
[self didChangeValueForKye:@"lastTime"];
- 独立的属性
如果你不想观察_lastTime而想观察_lastTimeString,可以通过一个类方法来做这项工作。
+ (NSSet *)keyPathsForValuesAffectingLastTimeString {
retutn [NSSet setWithObject:@"lastTime"];
}
注:摘自《Objective-C编程》(第2版)page 301