前言
KVO(key value observing),可以监听指定键,值的改变。与KVC相似,KVO也是以非正式协议的方式出现Foundation/NSKeyValueObserving.h
。
正文
相信大家对KVO的基本用法早已烂熟于心,这里不再介绍
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
在监听对象具体属性时,多数情况下会这样写
[obj addObserver:self forKeyPath:@"xxx" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
基于苹果的MVC
设计原理,KVO
最常出现的应用场景就是解耦View
和Model
。以上代码中obj
即Model
,self
即Controller
,当Model
内容出现变动告知Controller
,由Controller
再更新UI
。
先来看一幅从NSHipster上截取的表
KVO
中context:
后的参数是(void *)context
,很明显这里应该写NULL
而不是nil
接着context
继续说,这个参数好像并没有什么卵用,不然干嘛每次都传空?
试想这样一种情况,B -> A -> NSObject
,C -> NSObject
,C
中有属性obj
此时a、b同时观察c的obj属性,如果在某种情况下c的obj发生改变只想告知a而不告知b或者相反,这个时候怎么做?很简单,在B
中重写-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
,如果不重写怎么完成需求?这个时候context
就可以作为唯一标示符出场了。
同时还可以看到,obj的值改变后是先告知b再告知a的,也就是说谁最后观察谁最先被告知,类似于先进后出(这里与继承关系无关)。利用这一特性,又可以搞些小动作,比如跨类设置KVO的依赖
(后续文章会介绍同一类的不同属性如何设置KVO依赖)。
KVO
与通知
一样,可以是任意对象观察任意对象即“多对多”,observer
并不仅限于Controller
。