介绍
允许对象监听另一个对象特定属性的改变
KVO
一对一
NSNotificationCenter
一对多
KVO
可以监听单个属性的变化,也可以监听集合对象的变化
KVC
的mutableArrayValueForKey:
获得代理对象, 代理对象的内部对象发生改变时,会调用KVO
监听的方法.(NSArray, NSSet
)
流程
- 注册方法
addObserver: forKeyPath: options: context:
options:
NSKeyValueObservingOptionNew
NSKeyValueObservingOptionOld
NSKeyValueObservingOptionInitial
注册观察者后,立即调用一次
context:
传值
addObserver:
不会强引用, 所以要注意 - 监听方法
不实现会observeValueForKeyPath: ofObject: change: context:
crash
change
存放KVO
属性相关的值
change
中还有NSKeyValueChangeKindKey
字段, 和NSKeyValueChangeOldKey
平级关系,来提供本次更改的信息,对应NSKeyValueChange的value
.
若被观察者为集合,NSKeyValueChangeKindKey
中会包含NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, NSKeyValueChangeReplacement
的信息 - 移除方法
需要在观察者消失之前,否则会removeObserver: forKeyPath:
crash
兼容的调用方式
点语法和set
语法
[object setName:@""];
[object setValue:@"" forKey:@"name"];
[document setValue:@"" forKeyPath:@"object.name"];
Object *obj = [[Object alloc] init];
//获取代理集合
NSMutableArray *arrayM = [object mutableArrayValueForKey:@"name"];
[arrayM addObject:obj];
实际应用
KVO
在model
和controller
之间进行通信
注意点
KVO
中的addObserver
和removeObserver
成对
init
中add
,在dealloc
中remove
手动调用KVO
willChangeValueForKey:
didChangeValueForKey:
手动调用这两个方法
控制当前对象自动调用过程,可以重写
+ (BOOL)automaticallyNotifiesObserverForKey:(NSString *)theKey;
实现原理
isa-swizzling
在运行时根据原来创建一个中间类,这个中间类为原类的子类,动态修改当前对象的isa
指向中间类,并将class
方法重写,返回原来类的Class
NSKVONotifying_xxx
命名中间类
缺点
使用不当容易crash
: add
和remove
observer
被释放 keyPath
传错
keyPath
是字符串,修改属性不报错,可以使用NSStringFromSelector(@selector(isFinished))
.
KVO
不支持block
,可以使用Facebook
开源的KVOController
, 本质是对系统KVO
的封装,兼容block
和action