天天看點

iOS - KVO 鍵值觀察1、KVO2、KVO 的使用

KVO 是 Key-Value Observing 的簡寫,是鍵值觀察的意思,屬于 runtime 方法。Key Value Observing 顧名思義就是一種 observer 模式用于監聽屬性變量值的變化,也是運作時的方法,當執行個體變量改變時,系統會自動采取一些動作。KVO 跟 NSNotification 有很多相似的地方,用 addObserver:forKeyPath:options:context: 去 start observer, 用 removeObserver:forKeyPath:context 去 stop observer, 回調就是 observeValueForKeyPath:ofObject:change:context:。

對于 KVO 來說,我們要做的隻是簡單 update 我們的 property 的資料,不需要像 NSNotificationCenter 那樣關心是否有人在監聽你的請求,如果沒有人監聽該怎麼辦,所有 addObserver, removeObserver, callback 都是想要監聽的你的 property 的 class 做的事情。曾經做個項目,用 NSNotificationCenter post Notification 在一個 network callback 裡面,可是這時候因為最早的 addObserver 的 class 被釋放了,接着生成的 addObserver 的 class, 就接受到了上一個 observer 該監聽的事件,是以造成了錯誤,那時候的解決方案是為 addObserve key 做 unique,不會 2 次 addObserver 的 key 是相同的,但是有了 KVO, 我們同樣可以用 KVO 來完成,當 addOberver 的的 object remove 的時候,就不會有這樣的 callback 被調用了。

KVO 給我們提供了更少的代碼,和 NSNotification 比好處,不需要修改被觀察的 class, 永遠都是觀察你的人做事情。 但是 KVO 也有些毛病:

1、如果沒有 observer 監聽 keyPath, removeObsever:forKeyPath:context: 這個 keyPath, 就會 crash(崩潰), 不像 NSNotificationCenter removeObserver。

2、對代碼你很難發現誰監聽你的 property 的改動,查找起來比較麻煩。

3、對于一個複雜和相關性很高的 class,最好還是不要用 KVO, 就用 delegate 或者 notification 的方式比較簡潔。

KVO 使用分三步:

1、注冊成為觀察者。

2、觀察者定義 KVO 的回調。

3、移除觀察者。

KVO 使用注意:

KVO 是同步的,一旦對象的屬性發生變化,隻有用同步的方式,才能保證所有觀察者的方法能夠執行完成。KVO 監聽方法中,不要有太耗時的操作。

KVO 的方法調用,是在對應的線程中執行的。在子線程修改觀察屬性時,觀察者回調方法将在子線程中執行。

在多個線程同時修改一個觀察屬性的時候,KVO 監聽方法中會存在資源搶奪的問題,需要使用互斥鎖。如果涉及到多線程,KVO 要特别小心,通常 KVO 隻是做一些簡單的觀察和處理,千萬不要搞複雜了,KVO的監聽代碼,一定要簡單。

一定要删除觀察者,如果不删除觀察者,釋放對象,會直接崩潰。An instance 0x7fd340ebc400 of class KvoClass was deallocated while key value observers were still registered with it.

在 Swift 中使用 KVO 的前提條件:

1、觀察者和被觀察者都必須是 NSObject 的子類,因為 OC 中 KVO 的實作基于 KVC 和 runtime 機制,隻有是 NSObject 的子類才能利用這些特性;

2、觀察的屬性需要使用 dynamic 關鍵字修飾,表示該屬性的存取都由 runtime 在運作時來決定,由于 Swift 基于效率的考量預設禁止了動态派發機制,是以要加上該修飾符來開啟動态派發。

Objective-C

Swift

在實際工作中需要在合适的時候移除觀察者身份。