天天看點

深入了解 KVC\KVO 實作機制 — KVO

介紹iOS開發中常用的KVO的核心機制

KVC和KVO都屬于鍵值程式設計而且底層實作機制都是isa-swizzing,是以本來想放在一起講的。但是篇幅有限是以就分成了兩篇博文。 KVC實作機制傳送門

KVO概述

鍵值觀察Key-Value-Observer就是觀察者模式。

  • 觀察者模式的定義:一個目标對象管理所有依賴于它的觀察者對象,并在它自身的狀态改變時主動通知觀察者對象。這個主動通知通常是通過調用各觀察者對象所提供的接口方法來實作的。觀察者模式較完美地将目标對象與觀察者對象解耦。

當需要檢測其他類的屬性值變化,但又不想被觀察的類知道,有點像FBI監視嫌疑人,這個時候就可以使用KVO了。

KVO同KVC一樣都依賴于Runtime的動态機制

KVO實作步驟

  • 注冊
//keyPath就是要觀察的屬性值
//options給你觀察鍵值變化的選擇
//context友善傳輸你需要的資料
-(void)addObserver:(NSObject *)anObserver 
        forKeyPath:(NSString *)keyPath 
           options:(NSKeyValueObservingOptions)options 
           context:(void *)context
           
  • 實作方法
//change裡存儲了一些變化的資料,比如變化前的資料,變化後的資料;如果注冊時context不為空,這裡context就能接收到。
-(void)observeValueForKeyPath:(NSString *)keyPath 
                     ofObject:(id)object
                       change:(NSDictionary *)change 
                      context:(void *)context
           
  • 移除
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
           

KVO的實作分析

使用觀察者模式需要被觀察者的配合,當被觀察者的狀态發生變化的時候通過事先定義好的接口(協定)通知觀察者。在KVO的使用中我們并不需要向被觀察者添加額外的代碼,就能在被觀察的屬性變化的時候得到通知,這個功能是如何實作的呢?同KVC一樣依賴于強大的Runtime機制。

系統實作KVO有以下幾個步驟:

  • 當類A的對象第一次被觀察的時候,系統會在運作期動态建立類A的派生類。我們稱為B。
  • 在派生類B中重寫類A的setter方法,B類在被重寫的setter方法中實作通知機制。
  • 類B重寫會 class方法,将自己僞裝成類A。類B還會重寫dealloc方法釋放資源。
  • 系統将所有指向類A對象的isa指針指向類B的對象。

KVO同KVC一樣,通過 isa-swizzling 技術來實作。當觀察者被注冊為一個對象的屬性的觀察對象的isa指針被修改,指向一個中間類,而不是在真實的類。其結果是,isa指針的值并不一定反映執行個體的實際類。

是以不能依靠isa指針來确定對象是否是一個類的成員。應該使用class方法來确定對象執行個體的類。