iOS开发 - 分享一个关于KVO的扩展

typealias KVONotificationBlock = (Any?, _ oldValue: Any?, _ value: Any?) -> Void

extension NSObject {
    //默认的函数,option的初始值是Initial|New, 监测打变化的值默认转到主线程
    func observe(_ object: Any?, keyPath: String, block: @escaping KVONotificationBlock) {
        self.kvoController.observe(object, keyPath: keyPath, options:[.initial, .new], block:{(observer: Any?, object: Any, change: [String: Any]) in
            DispatchQueue.main.async(execute: { () -> Void in
                block(observer, change["old"], change["new"]);
            })
        })
    }
    
    func observe(_ object: Any?, keyPath: String, options: NSKeyValueObservingOptions, mainThread: Bool, block: @escaping KVONotificationBlock) {
        self.kvoController.observe(object, keyPath: keyPath, options: options) { (observer, object, change: [String: Any]) -> Void in
            if !mainThread || Thread.isMainThread == true  {
                block(observer, change["old"], change["new"]);
            } else {
                DispatchQueue.main.async(execute: { () -> Void in
                    block(observer, change["old"], change["new"]);
                })
            }
        }
    }
    
    func removeObserve(_ object: Any?, path: String) {
        self.kvoController.unobserve(object, keyPath: path);
    }
    
    func removeObserve(_ obj: Any?) {
        self.kvoController.unobserve(obj);
    }
    
    func removeAll() {
        self.kvoController.unobserveAll();
    }
}
  • kvoController是啥?
    FBKVOController是Facebook开源的替代KVO的解决方案。它用block解决了以前使用KVO时代码散乱的缺点。可以利用CocoaPods,pod 'KVOController',到自己的工程中。
  • 为什么能直接self.kvoController?
    因为在FBKVOController中,有一个NSObject+FBKVOController扩展,kvoController是成员变量,所以NSObject能用.语法,拿到kvoController。


    Paste_Image.png
  • 为啥要用FBKVOController?
    大家都知道,kvo 全称 key-value observing,由 cocoa 框架提供的支持观察者模式的技术,结合 Objective-C 非常易用,在很多场合都可以有效地替换 NSNotificationCenter。但其也有一些致命的缺点,就是很容易导致引发 crash。譬如:只有addObserver,没有removeObserver。addObserver 和 removeObserver 必须配对出现,不然的话,等待你的就是crash。其调用的顺序:必须先添加观察者,然后处理业务,最后完成后移除观察者,释放掉观察者。removeObserver方法的调用,一般在dealloc()(OC)、deinit()(Swift)中。
    而FBKVOController则是帮助我们更好的使用KVO。
    FBKVOController生命周期跟观察者绑定,则观察者释放时,由FBKVOController生成的实例也被释放,从 _FBKVOSharedController 移除对应的观察者信息,避免发消息给已释放观察者导致的crash。
  • 为啥要写这个扩展?
    还不为了好用,省心省事呗,啊哈哈。在控制器中直接调用observe方法,传入对应的参数,在block回调中做该做的事情就可以。当然,也不需要在controller的dealloc(OC)或者deinit(Swift)方法中,调用removeObserver方法。例如下面的代码:
observe(scrollView, keyPath: #keyPath(UIScrollView.contentOffset)) { [weak self] (weakSelf, oldValue, newValue) in
// 处理事情
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • KVO 作为 iOS 中一种强大并且有效的机制,为 iOS 开发者们提供了很多的便利;我们可以使用 KVO 来检测...
    JzRo阅读 983评论 0 2
  • 写在前面 程序设计语言中有各种各样的设计模式(pattern)和与此对应的反设计模式(anti-pattern),...
    Frankxp阅读 4,966评论 0 23
  • KVO 作为 iOS 中一种强大并且有效的机制,为 iOS 开发者们提供了很多的便利;我们可以使用 KVO 来检测...
    Draveness阅读 6,921评论 11 59
  • 大白健康系统--iOS APP运行时Crash自动修复系统 前言 大白(Baymax),迪士尼动画《超能陆战队》中...
    鼠犬玉阅读 17,541评论 22 158
  • 上半年有段时间做了一个项目,项目中聊天界面用到了音频播放,涉及到进度条,当时做android时候处理的不太好,由于...
    DaZenD阅读 3,046评论 0 26