ing_XGPerson.h"
// KVO的原理伪代码实现
@implementation NSKVONotifying_XGPerson
- (void)setAge:(int)age{
_NSSetIntValueAndNotify();
}
- (void)_NSSetIntValueAndNotify{
// KVO的调用顺序
[self willChangeva lueForKey:@"age"];
[super setAge:age];
// KVO会在didChangeva lueForKey里面调用age属性变更的通知回调
[self didChangeva lueForKey:@"age"];
}
- (void)didChangeva lueForKey:(NSString *)key{
// 通知监听器,某某属性值发生了改变
[oberser observeva lueForKeyPath:key ofObject:self change:nil context:nil];
}
// 会重写class返回父类的class
// 原因:1.为了隐藏这个动态的子类 2.为了让开发者不那么迷惑
- (Class)class{
return [XGPerson class];
}
- (void)dealloc{
// 回收工作
}
- (BOOL)_isKVOA{
return YES;
}
如何手动调用KVO
其实通过上面的代码大家已经知道了KVO是怎么触发的了,那怎么手动调用呢?很简单,只要调用两个方法就行了,如下:
[self.person1 willChangeva lueForKey:@"age"];
[self.person1 didChangeva lueForKey:@"age"];
但是上面说调用顺序的时候,好像明明KVO是在 didChangeVlaueForKey 里面调用的,为什么还要调用 willChangeVlaueForKey呢?
那是因为KVO调用的时候会去判断这个对象有没有调用 willChangeVlaueForKey 只有调用了这个之后,再调用 didChangeVlaueForKey 才能真正触发KVO
直接修改成员变量会触发KVO吗?
答案是不会的,为什么呢?因为KVO是通过修改set方法实现来触发的,一个成员变量都没有 set 方法,所以肯定是不会触发了.
总结
KVO是通过runtime机制动态的给要添加KVO监听的对象创建一个子类,并且让instance对象的isa指向这个全新的子类.
当修改instance对象的属性时,会调用Foundation的_NSSetXXXValueAndNotify函数,顺序如下:
- willChangeva lueForKey:
- 父类原来的setter
- didChangeva lueForKey:
didChangeva lueForKey 内部会触发监听器(Oberser)的监听方法( observeva lueForKeyPath:ofObject:change:context:)
通过这个子类重写一些父类的方法达到触发KVO回调的目的.
补充
KVO是使用了典型的发布订阅者设计模式实现事件回调的功能,多个订阅者,一个发布者,简单的实现如下:
1> 订阅者向发布者进行订阅.
2> 发布者将订阅者信息保存到一个集合中.
3> 当触发事件后,发布者就遍历这个集合分别调用之前的订阅者,从而达到1对多的通知.
以上已全部完毕,如有什么不正确的地方大家可以指出~~ ^_^ 下次再见~~
|