前几天写了一个下拉刷新的控件YiRefresh用到了KVO,以前从不知道为什么别人说少用它。现在才知道真的要少用这个黑科技。文中的代码多事YiRefresh的。
先看一下我为什么要黑它,因为它让我看到了这个。
查看图片

先说一下基本用法
step1

1
2
//    为_scrollView设置KVO的观察者对象,keyPath为contentOffset属性
    [_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];

step2

1
2
3
4
5
//当属性的值发生变化时,自动调用此方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
    if (![@"contentOffset" isEqualToString:keyPath]) return; 
}

完了,好像还有一个step3,先不添加,我们发现在YiRefresh的UITableView、UICollectionView的场景下不会出什么错,然后我就commit了。
然后今天想把UIWebView的使用场景加上去,因为UIWebView有一个属性scrollView,所以我就这样加了。

1
2
3
4
5
6
7
8
9
10
    //    YiRefreshHeader  头部刷新按钮的使用
    refreshHeader=[[YiRefreshHeader alloc] init];
    refreshHeader.scrollView=webView.scrollView;
    [refreshHeader header];
    refreshHeader.beginRefreshingBlock=^(){
 
        [webView loadRequest:[[NSURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:@"http://www.coderyi.com/"]]];
 
 
    };

到这里其实还是不会出现问题,shit!但是当block里面为空时,错误就来了。

思量很久之后,我就把传说中的step3加上
step3

1
2
3
-(void)dealloc{
[_scrollView removeObserver:self forKeyPath:@"contentOffset"];
}

因为我发现只有被观察对象不是直接的对象UITableView或者UICollectionView而是UIWebView的scrollView的属性的时候,它才调用dealloc,并且这个时候如果不removeObserver就回报错。
这是因为UIWebView的scrollView作为属性时被retain了。
所以对于这个黑科技,不管被观察对象有没有被retain,都应该Observer对象和Observer者一一对应,多一个少一个都会报错,而且是闪退这种无法容忍的错。
KVO它来源于设计模式中的观察者模式,KVO是有一点用处的,KVO有时候会适用于Model和View的通信,就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。
关于KVO的原理,这里可以简单说一下(引用自sunnyxx的objc kvo简单探索):
1、当一个object有观察者时,动态创建这个object的类的子类
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类

这里还想对比一下KVO、NSNotification以及delegate,KVO、NSNotification都是观察者模式,可以一对多,并且不关注返回值;delegate是代理模式,只能一对一,关注返回值。
delegate的效率可能要比那两个高一点,而且也主张多用delegate,不过有时候它也会出错,所以需要在dealloc中置该对象的delegate为nil。
文章可能有不对不清楚的地方,请读者指教。
更多KVO的吐槽看这里,轻量级KVO[译]
KVO的详细使用看这里, [深入浅出Cocoa]详解键值观察(KVO)及其实现机理
更多黑科技看这里,ARC 下内存泄露的那些点