KVO
和NSNotificationCenter
都是iOS
中观察者模式
的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO是一对一
的,而NSNotificationCenter是一对多
的。KVO
对被监听对象无侵入性,不须要修改其内部代码便可实现监听。git
KVO
底层实现 KVO
是基于runtime
机制实现的,运用了一个isa-swizzling
技术。isa-swizzling
就是类型混合指针机制
, 将2个对象的isa
指针互相调换, 就是俗称的黑魔法第一次被观察
时,系统就会在运行期动态
地建立该类的一个派生类
,在这个派生类中重写基类中任何被观察属性的setter
方法。派生类在被重写的setter
方法内实现真正的通知机制
Person
,那么生成的派生类名为NSKVONotifying_Person
,每一个类对象中都有一个isa指针
指向当前类,当一个类对象第一次被观察,那么系统会偷偷将isa指针
指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter
方法NSObject
的两个方法:willChangeValueForKey:
和didChangevlueForKey:
;在一个被观察属性发生改变以前,willChangeValueForKey:
必定会被调用,这就会记录旧的值。而当改变发生后,didChangeValueForKey:
会被调用,继而observeValueForKey:ofObject:change:context:
也会被调用KVO
的这套实现机制中苹果还偷偷重写了class
方法,让咱们误认为仍是使用的当前类,从而达到隐藏生成的派生类KVO
手动调用willChangeValueForKey:
和didChangeValueForKey:
示例代码以下:一、自动
//默认返回YES
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
if ([key isEqualToString:@"age"]) {
return NO;//不观察age属性值得变化
}
return YES;
}
二、手动
- (void)setName:(NSString *)name{
[self willChangeValueForKey:@"name"];
_name = name;
[self didChangeValueForKey:@"name"];
}
复制代码
KVO
吗 不会触发KVO
,添加KVO
的Person
实例,实际上是NSKVONotyfing_Person
类在调用setter
方法,不是调用Person
的setter
方法,而是NSKVONotyfing_Person
的setter
方法,由于修改为员变量不是setter
方法赋值Person
类进行了监听,也建立了一个NSKVONotifying_Person
类,那么会编译经过么 编译经过,由于KVO
是运行时刻建立的,并不在编译时刻,在编译时刻只有一个NSKVONotifying_Person
,因此不报错,能够经过,可是此时KVO
起不了做用
附:个人博客地址github