前几天写了一个下拉刷新的控件 YiRefresh 用到了KVO,以前从不知道为什么别人说少用它。现在才知道真的要少用这个黑科技。文中的代码多事YiRefresh的。
先看一下我为什么要黑它,因为它让我看到了这个。
先说一下基本用法
step1
// 为_scrollView设置KVO的观察者对象,keyPath为contentOffset属性 [_scrollView addObserver:self forKeyPath:@"contentOffset" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
step2
//当属性的值发生变化时,自动调用此方法 - (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,所以我就这样加了。
// 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
-(void)dealloc{ [_scrollView removeObserver:self forKeyPath:@"contentOffset"]; }
因为我发现只有被观察对象不是直接的对象UITableView或者UICollectionView而是UIWebView的scrollView的属性的时候,它才调用dealloc,并且这个时候如果不removeObserver就回报错。
这是因为UIWebView的scrollView作为属性时被retain了。
所以对于这个黑科技,不管被观察对象有没有被retain,都应该Observer对象和Observer者一一对应,多一个少一个都会报错,而且是闪退这种无法容忍的错。
KVO它来源于设计模式中的观察者模式,KVO是有一点用处的,KVO有时候会适用于Model和View的消息传递,就像上边的例子那样,当更改属性的值后,监听对象会立即得到通知。
文章可能有不对不清楚的地方,请读者指教。