IOS KVO

作者: chenhh6701 | 来源:发表于2017-06-19 15:23 被阅读46次

    刚入坑的小白,一开始以为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];
        }
    }
    

    参考:
    https://objccn.io/issue-7-3/

    相关文章

      网友评论

        本文标题:IOS KVO

        本文链接:https://www.haomeiwen.com/subject/fcggqxtx.html