刚入坑的小白,一开始以为KVO完全可以用代理模式替代,在MJRefreshComponent中看了KVO的代码后,突然明白KVO比我想象的强大。
对比代理的优势:
1.他不需要在被监控类中添加Delegate,被监控的类完全不需要知道定义的业务逻辑,不过需要添加addObserver 和 removeObserver。
2.KVO中被监控的类可以被多个对象监控,而代理模式只有一个delegate(除非你再写一个list,这样添加了被监控对象的功能,不实际)。
代理的优势:
1.KVO只监听值的更改,而delegate一般带有业务逻辑(对应值变化不同有不同的方法)
注意点:
1.一个需要注意的地方是,KVO 行为是同步的,并且发生与所观察的值发生变化的同样的线程上,不推荐把 KVO 和多线程混起来。
方法:
// 该键名 所依赖的其他键 (其他键更改,该键也会调用一直set)
- (NSSet *)keyPathsForValuesAffecting<键名>
- (void)willChangeValueForKey:(NSString *)key
- (void)didChangeValueForKey:(NSString *)key
NSKeyValueObservingOptions
KVO的使用:
在MJRefreshComponent的使用
// 添加监控
- (void)addObservers
{
NSKeyValueObservingOptions options = NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld;
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentOffset options:options context:nil];
[self.scrollView addObserver:self forKeyPath:MJRefreshKeyPathContentSize options:options context:nil];
self.pan = self.scrollView.panGestureRecognizer;
[self.pan addObserver:self forKeyPath:MJRefreshKeyPathPanState options:options context:nil];
}
// 移除监控
- (void)removeObservers
{
[self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentOffset];
[self.superview removeObserver:self forKeyPath:MJRefreshKeyPathContentSize];;
[self.pan removeObserver:self forKeyPath:MJRefreshKeyPathPanState];
self.pan = nil;
}
// 对应值的更改
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
// 遇到这些情况就直接返回
if (!self.userInteractionEnabled) return;
// 这个就算看不见也需要处理
if ([keyPath isEqualToString:MJRefreshKeyPathContentSize]) {
[self scrollViewContentSizeDidChange:change];
}
// 看不见
if (self.hidden) return;
if ([keyPath isEqualToString:MJRefreshKeyPathContentOffset]) {
[self scrollViewContentOffsetDidChange:change];
} else if ([keyPath isEqualToString:MJRefreshKeyPathPanState]) {
[self scrollViewPanStateDidChange:change];
}
}
网友评论