[iOS] KVO(NSKeyValueObserving)、KVC(NSKeyValueCoding)作用淺談 在很多時候接觸到很多地方都有對KVC,KVO的描述,但是都是一筆帶過。只知道這是Object-C提供的一個不錯的機制,可以很好的減少澆水代碼。
其實KVC、KVO即NSKeyValueCoding和NSKeyValueObserving的簡稱。
在官方文檔中描述為
那我們KVO、KVC用來做什麼的我們又怎麼使用它呢?
首先我們先瞭解下KVO的機制
KVO:當指定的對象的屬性被修改了,允許對象接收到通知的機制。每當在類中定義一個監聽
如:
[self addObserver:self
forKeyPath:@"items"
options:0
context:contexStr];
***
當然你還可以監聽其他對象的屬性變化
[person addObserver:money
forKeyPath:@"account"
options:0
context:contexStr];
****
只要當前類中items這個屬性發生的變化都會觸發到以下的方法。
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
KVO的優點:
當有屬性改變,KVO會提供自動的訊息通知。這樣開發人員不需要自己去實現這樣的方案:每次屬性改變了就發送訊息通知。
這是KVO機制提供的最大的優點。因為這個方案已經被明確定義,獲得架構級支援,可以方便地採用。
開發人員不需要添加任何代碼,不需要設計自己的觀察者模型,直接可以在工程裡使用。
其次,KVO的架構非常的強大,可以很容易的支援多個觀察者觀察同 一個屬性,以及相關的值。
KVC的實現分析
KVC運用了一個isa-swizzling技術。
isa-swizzling就是類型混合指標機制。KVC主要通過isa-swizzling,來實現其內部尋找定位的。
isa指標,就是is a kind of的意思,指向維護分發表的對象的類。該分發表實際上包含了指向實作類別中的方法的指標,和其它資料。
如下KVC的代碼:
[person setValue:@"personName" forKey:@"name"];
就會被編譯器處理成:
SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (person->isa,sel);
method(person, sel, @"personName", @"name");
***
其中:
SEL資料類型:它是編譯器運行Objective-C裡的方法的環境參數。
IMP資料類型:他其實就是一個 編譯器內部實現時候的函數指標。當Objective-C編譯器去處理實現一個方法的時候,就會指向一個IMP對象,這個對象是C語言表述的類型。
***
KVC在調用方法setValue的時候
(1)首先根據方法名找到運行方法的時候所需要的環境參數。
(2)他會從自己isa指標結合環境參數,找到具體的方法實現的介面。
(3)再直接尋找得來的具體的方法實現。
這樣的話前面介紹的KVO實現就好理解了
當一個對象註冊了一個觀察者,被觀察對象的isa指標被修改的時候,isa指標就會指向一個中間類,而不是真實的類。
所以isa指標其實不需要指向執行個體對象真實的類。所以我們的程式最好不要依賴於isa指標。在調用類的方法的時候,最好要明確對象執行個體的類名。
這樣只有當我們調用KVC去訪問key值的時候KVO才會起作用。所以肯定確定的是,KVO是基於KVC實現的。
zz from: http://chinaxxren.iteye.com/blog/1150430