typealias KVONotificationBlock = (Any?, _ oldValue: Any?, _ value: Any?) -> Void
extension NSObject {
//默認(rèn)的函數(shù)躏精,option的初始值是Initial|New, 監(jiān)測打變化的值默認(rèn)轉(zhuǎn)到主線程
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洛口。
- 為啥要用FBKVOController凯沪?
大家都知道,kvo 全稱 key-value observing挺举,由 cocoa 框架提供的支持觀察者模式的技術(shù)身笤,結(jié)合 Objective-C 非常易用,在很多場合都可以有效地替換 NSNotificationCenter液荸。但其也有一些致命的缺點,就是很容易導(dǎo)致引發(fā) crash伤柄。譬如:只有addObserver,沒有removeObserver适刀。addObserver 和 removeObserver 必須配對出現(xiàn),不然的話笔喉,等待你的就是crash取视。其調(diào)用的順序:必須先添加觀察者常挚,然后處理業(yè)務(wù),最后完成后移除觀察者折欠,釋放掉觀察者吼过。removeObserver方法的調(diào)用,一般在dealloc()(OC)盗忱、deinit()(Swift)中。
而FBKVOController則是幫助我們更好的使用KVO斤葱。
FBKVOController生命周期跟觀察者綁定揖闸,則觀察者釋放時,由FBKVOController生成的實例也被釋放汤纸,從 _FBKVOSharedController 移除對應(yīng)的觀察者信息,避免發(fā)消息給已釋放觀察者導(dǎo)致的crash楞慈。 - 為啥要寫這個擴展啃擦?
還不為了好用,省心省事唄令蛉,啊哈哈狡恬。在控制器中直接調(diào)用observe方法蝎宇,傳入對應(yīng)的參數(shù),在block回調(diào)中做該做的事情就可以兔乞。當(dāng)然凉唐,也不需要在controller的dealloc(OC)或者deinit(Swift)方法中,調(diào)用removeObserver方法熊榛。例如下面的代碼:
observe(scrollView, keyPath: #keyPath(UIScrollView.contentOffset)) { [weak self] (weakSelf, oldValue, newValue) in
// 處理事情