天天看點

iOS概念之KVO(Key-Value Observing)

轉:http://ningandjiao.iteye.com/blog/2009729

在一個複雜的,有狀态的系統中,當一個對象的狀态發生改變,如何通知系統,并對狀态改變做出相應的行為是必需考慮的一個問題,在iOS中為這類問題提供了4種解決方法: 

1. NSNotifiactaion和NSNotificationCenter:通知中心 

2. Delegates:代理, 

3. Callback:回調, 

4. KVO(Key-Value Observing):鍵值觀察 

這篇文章就來說說通過KVO通知系統狀态發生改變的用法。 

KVO是什麼? 

KVO是Object-C中定義的一個通知機制,其定義了一種對象間監控對方狀态的改變,并做出反應的機制。對象可以為自己的屬性注冊觀察者,當這個屬性的值發生了改變,系統會對這些注冊的觀察者做出通知。其用途十分廣泛,比方說,你的下載下傳進度條是根據下載下傳百分比決定的,那麼,可以通過觀察下載下傳百分比的改變,重新整理進度條的樣式,來直覺的反應下載下傳進度等等。 

KVO的用法 

根據上面的描述,一個KVO的用法主要就涉及3個部分: 

1. 為對象的屬性注冊觀察者:對象通過調用下面這個方法為屬性添加觀察者 

Object-c代碼  

iOS概念之KVO(Key-Value Observing)
  1. - (void)addObserver:(NSObject *)observer  
  2.          forKeyPath:(NSString *)keyPath  
  3.             options:(NSKeyValueObservingOptions)options  
  4.             context:(void *)context  
  • observer: 觀察者對象. 其必須實作方法observeValueForKeyPath:ofObject:change:context:.
  • keyPath: 被觀察的屬性,其不能為nil.
  • options: 設定通知觀察者時傳遞的屬性值,是傳改變前的呢,還是改變後的,具體的設定可以這兒:https://developer.apple.com/library/mac/documentation/Cocoa/Reference/Foundation/Protocols/NSKeyValueObserving_Protocol/Reference/Reference.html#//apple_ref/doc/c_ref/NSKeyValueObservingOptions,通常設定為NSKeyValueObservingOptionNew。
  • context: 一些其他的需要傳遞給觀察者的上下文資訊,通常設定為nil

2. 觀察者接收通知,并做出處理:觀察者通過實作下面的方法,完成對屬性改變的響應: 

Object-c代碼  

iOS概念之KVO(Key-Value Observing)
  1. - (void)observeValueForKeyPath:(NSString *)keyPath  
  2.                       ofObject:(id)object  
  3.                         change:(NSDictionary *)change  
  4.                        context:(void *)context  
  • keyPath: 被觀察的屬性,其不能為nil.
  • object: 被觀察者的對象.
  • change: 屬性值,根據上面提到的Options設定,給出對應的屬性值
  • context: 上面傳遞的context對象。

3. 清除觀察者:對象通過下面這個方法移除觀察者: 

Object-c代碼  

iOS概念之KVO(Key-Value Observing)
  1. - (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath  

4.  注意事項: 

使用KVO消息傳遞機制有兩個要求:(1)觀察者必須知道被觀察對象,即在同一作用域。(2)觀察者還需要知道被觀察對象的生命周期,因為在銷毀發送者對象之前,需要取消觀察者的注冊。 

另外:如果計劃在Core Data對象上使用KVO,需要知道這跟一般的KVO使用方法有點不同。還必須結合Core Data的故障機制(faulting mechanism),一旦core data出現了故障,它将會觸發其屬性對應的觀察者(即使這些屬性值沒有發生改變)。 

5.  一些好的實踐 

  • (1)當一個觀察者觀察多個對象的相同屬性(即不同Object,但是KeyPath相同),可通過設定靜态的Context變量來區分不同的通知。
  • (2)使用NSStringFromSelector(@selector(method))來擷取KeyPath,而不是直接通過NSString寫屬性名,這樣編譯器可以幫助發現屬性名中的Typo。
  • (3)通過方法:+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key,通過一個Key觀察多個屬性值的改變。

和n otification的差別也是在,KVO是對象之間直接的互動,而notification需要notificationCenter來做為中間互動。