8.1: kvo 與 kvc 展開
? ? ?1:KVO
? ? ? ? ? ? KVO(Key-Value-Observing)鍵值觀察总棵,其技術(shù)原理就是通過 isa waizzle 技術(shù)添加被觀察對象中間類盗棵,并重新寫相應(yīng)的方法來監(jiān)聽鍵值變化牡肉。當(dāng)被觀察的對象屬性被修改后搏讶,則對象回接收到通知,即每次指定的被觀察對象的屬性被修改后呼巴,kvo就會自動通知相應(yīng)的觀察者影钉。
? ? ? ? ? ? isa swizzle 不同于method swizzle,其交換的是isa,對象的isa 指針式定義了它的類录粱,所以ISA swizzling 指修改對象所指向的類腻格,KVO則是使用該技術(shù)實現(xiàn)的,還有zombie objects檢測也用到了該技術(shù),而method swizzle交換的是method
? ? ? ? 2:KVO引起的crash 情況如下
? ? ? ? ? ? 2.1* observer 已銷毀啥繁,但是未及時移除監(jiān)聽荒叶;
? ? ? ? ? ? 2.2* addObserver 與 removeObserver 不匹配
? ? ? ? ? ? ? ? 1:移除了未注冊的觀察者,但是未及時移除監(jiān)聽
? ? ? ? ? ? ? ? 2:重復(fù)移除多次输虱,移除次數(shù)多于添加次數(shù)些楣,導(dǎo)致崩潰。
? ? ? ? ? ? ? ? 3:重復(fù)添加多次宪睹,雖然不會崩潰愁茁,但是發(fā)生改變時,也同時會被觀察多次亭病。
? ? ? ? ? ? 2.3*添加了觀察者鹅很,但未實現(xiàn)observerValueForKeyPath:ofObject:change:context: 方法,導(dǎo)致崩潰.
? ? ? ? ? ? 2.4*添加或移除時 keypath == nil 罪帖,導(dǎo)致崩潰.
? ? ? ? 通過如上場景就可以發(fā)現(xiàn)其實kvo 崩潰的主要原因是觀察者管理混亂促煮,特別是觀察者關(guān)系復(fù)雜時邮屁,開發(fā)者容易導(dǎo)致混亂。
? ? ? ? ? ? 如下圖所示:
? ? ? ? 那如何管理呢菠齿? 既然觀察者都是開發(fā)者來管理佑吝,由人來管理必然會出現(xiàn)失誤的時候,那我們是否能通過一個代理對象來管理绳匀?
? ? ? ? ? ? 答案:yes芋忿!
? ? ? ? 3:具體實現(xiàn)如下:
? ? ? ? ? ? 1:通過Method Swizzle方法調(diào)配交換KVO相應(yīng)的方法到NSObject基類,如下:
? ? ? ? ? ? 2: 然后在觀察者和被觀察者之間建立一個 KVODelegate 對象疾棵,
? ? ? ? ? ? ? ? 兩者之間通過 KVODelegate 對象 建立聯(lián)系戈钢。然后在添加和移除操作時,
? ? ? ? ? ? ? ? 將 KVO 的相關(guān)信息例如 observer是尔、keyPath殉了、options、context 保存為 KVOInfo 對象拟枚,并添加到 KVODelegate 對象 中對應(yīng) 的 關(guān)系哈希表 中宣渗,對應(yīng)原有的添加觀察者。
? ? ? ? ? ? 3: 在添加和移除操作的時候梨州,
? ? ? ? ? ? ? ? 利用 KVODelegate 對象 做轉(zhuǎn)發(fā)痕囱,
? ? ? ? ? ? ? ? 把真正的觀察者變?yōu)?KVODelegate 對象,
? ? ? ? ? ? ? ? 而當(dāng)被觀察者的特定屬性發(fā)生了改變(會被調(diào)用到observeValueForKeyPath:ofObject)暴匠,
? ? ? ? ? ? ? ? 再由 KVODelegate 對象分發(fā)到原有的觀察者上鞍恢。
? ? ? ? ? ? 4:為了避免被觀察者提前被釋放,
? ? ? ? ? ? ? ? 被觀察者在 dealloc 時仍然注冊著 KVO 導(dǎo)致崩潰每窖。
? ? ? ? ? ? ? ? BayMax 系統(tǒng)還利用 Method Swizzling 實現(xiàn)了自定義的 dealloc帮掉,
? ? ? ? ? ? ? ? 在系統(tǒng) dealloc 調(diào)用之前,將多余的觀察者移除掉窒典。
? 8.1.2:KVC
? ? ? KVC(Key Value Coding)鍵值編碼蟆炊,提供一種機制來間接訪問對象的屬性,而不是通過Setter/Getter方法進行訪問瀑志。
? ? ? 通常導(dǎo)致崩潰的原因不外乎鍵值設(shè)置不正確涩搓,如下:
? ? ? ? ? 1. key 不是對象的屬性
? ? ? ? ? 2. keyPath 不正確
? ? ? ? ? 3. value 為 nil,為非對象設(shè)值
? ? ? ? ? 4. key 為 nil
? ? ? 那如何防護呢劈猪,熟悉KVC機制的同學(xué)肯定清楚:runtime提供了相應(yīng)的補救措施來避免應(yīng)用崩潰昧甘,包括如下:
? ? ? ? ? ? setValue:forKey: 找不到相應(yīng)的key會調(diào)用 setValue: forUndefinedKey: 方法;
? ? ? ? ? ? valueForKey: 找不到相應(yīng)的keyPath會調(diào)用 valueForUndefinedKey: 方法战得;
? ? ? ? ? ? setValue:forKey:添加value為nil方法充边,會調(diào)用setNilValueForKey方法來避免;
? ? ? 因此常侦,針對上面崩潰的前3中場景浇冰,就可以通過分辨實現(xiàn)上述三種方法來避免贬媒,但對于key為nil的情況該如何防護呢?
? ? ? ? ? ? 這里直接告訴答案:毅然是通過熟悉的Method Swizzle來替換原有的
? ? ? ? ? ? setValue:forKey:方法肘习,
? ? ? ? ? ? 并判斷傳入的key是否為nil际乘。具體代碼如下: