前言html
蘋果的KVO鍵值觀察機制在平常開發中很常見,可是系統提供的API卻不支持block回調;再加上添加觀察者addObserver:forKeyPath:options:context:只能觀察一個鍵值,而且還要手動的移除鍵值觀察,這些存在的問題致使開發者對現有的機制十分的不滿意,涌現出不少的解決方案,本身實現KVO機制(runtime)以及今天要介紹的KVOController庫,KVOController是由FaceBook開源的一個KVO庫,經過封裝系統的KVO機制,可以支持block回調以及隱式移除鍵值監聽等功能,支持設置多個KeyPaths,並且線程安全。ios
KVOController使用git
詳細的介紹不是今天要講述的內容,網絡上有不少的文章,分析了其源碼的邏輯,大體原理將鍵值觀察信息封裝至_FBKVOInfo對象,而後在FBKVOController類中維護着_objectInfosMap表,類型爲NSMapTable(是一種相似於NSDictionary的數據結構,能夠對Key和Value進行內存管理),Key爲observing被觀察者對象,最後經過_FBKVOSharedController類,實現鍵值監聽以及回調;當前的控制器被釋放掉後,會自動執行鍵值觀察移除操做,由於FBKVOController對象經過runtime關聯當前控制器。github
//簡單的使用 [self.KVOController observe:hashObject keyPath:@"className" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld block:^(id _Nullable observer, id _Nonnull object, NSDictionary<NSString *,id> * _Nonnull change) { NSLog(@"str -- %@", change[NSKeyValueChangeNewKey]); }]; hashObject.className = @"有點意思"; observe是被觀察的對象,觀察者對象是_FBKVOSharedController這個對象。
KVO崩潰的通常緣由安全
一、被觀察者被釋放了(被觀察者對象是一個局部變量);網絡
二、觀察者被釋放了,可是沒有移除鍵值監聽;數據結構
三、註冊的監聽沒有被移除掉,又從新註冊了一遍監聽;app
官網上也有說明,If your app targets iOS 9.0 and later or macOS 10.11 and later, you don't need to unregister an observer in its deallocation method. If your app targets earlier releases, be sure to invoke removeObserver:name:object: before observer or any object specified in addObserver:selector:name:object: is deallocated.大概意思,iOS9以前的系統,必需要在觀察者對象被釋放以前顯式執行移除鍵值觀察邏輯(緣由2)。線程
問題分析code
NSMapTable能夠由開發者自行的設置管理內存的方案,當使用WeakMemory時即便用self.KVOControllerNonRetaining對象去設置鍵值觀察時,當前控制器Pop後程序會直接crash,緣由是因爲被觀察者對象被釋放掉,致使_objectInfosMap表中的內容自動移除,爲何會這樣?官方文檔中有解釋,The major option is to have keys and/or values held 「weakly」 in a manner that entries are removed when one of the objects is reclaimed.大概的意思就是,當key或者是value使用weak內存管理時,只要key或者value對象被釋放,當前的記錄將會被移除。記錄被移除後,執行_unobserveAll移除鍵值觀察邏輯時,沒法移除已註冊的鍵值觀察,由於保存在_objectInfosMap中的信息被移除掉了。結合KVO的崩潰的緣由,形成崩潰是由被觀察者被釋放致使。
建議
所以在使用KVOController庫時,儘可能的使用self.KVOController對象去綁定鍵值觀察,由於_objectInfosMap會持有observing對象並不會當即釋放掉,直到執行完移除鍵值觀察後,清除_objectInfosMap記錄,纔會被釋放掉,這樣就不會形成Pop控制器致使系統crash的問題,其餘的方法在KVOController的github地址的issues中有討論,感興趣的開發者能夠關注。