注销观察者 [_message removeObserver:self forKeyPath:kKVOPathKey];
KVO实现原理
一般情况下对于使用Property的属性,objc会为其自动添加键值观察功能,你只需要写一句@property (noatomic, assign) float age 就能够获得age的键值观察功能。而为了更深入的探讨一下,KVO的实现原理我们先手动实现一下KVO:
@implementation DZKVOManual
- (void) setAge:(int)age
{
[self willChangeValueForKey:kKVOPathAge];
if (age !=_age) {
_age = age;
}
[self didChangeValueForKey:kKVOPathAge];
}
//经验证 会先去调用automaticallyNotifiesObserversForKey:当该函数没有时才会调用automaticallyNotifiesObserversOfAge。这个函数应该是编译器,自动增加的一个函数,使用xcode能够自动提示出来。的确很强大。
//+(BOOL) automaticallyNotifiesObserversOfAge
//{
// return NO;
//}
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key
{
if (key ==kKVOPathAge) {
return NO;
}
return [super automaticallyNotifiesObserversForKey:key];
}
@end
首先,需要手动实现属性的 setter 方法,并在设置操作的前后分别调用 willChangeValueForKey: 和 didChangeValueForKey方法,这两个方法用于通知系统该 key 的属性值即将和已经变更了;
其次,要实现类方法 automaticallyNotifiesObserversForKey,并在其中设置对该 key 不自动发送通知(返回 NO 即可)。这里要注意,对其它非手动实现的 key,要转交给 super 来处理。
在这里的手动实现,主要是手动实现了主题对象变更向外广播的过程。后续如何广播到观察者和观察者如何响应我们没有实现,其实这两个过程apple已经封装的很好了,猜测一下的话,应该是主题对象会维护一个观察者的队列,当本身属性发生变动,接受到通知的时候,找到相关属性的观察者队列,依次调用observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context来广播更改。 还有一个疑问,就是在自动实现KVO的时候,系统是否和我们手动实现做了同样的事情呢?
自动实现KVO及其原理
我们仔细来观察一下在使用KVO的过程中类DZMessage的一个实例发生了什么变化: 在使用KVO之前:










