本文摘錄自部落格:寫得非常不錯,想要深入研究,可研讀原部落格
kvo**於設計模式中的觀察者模式,其基本思想就是:乙個目標物件管理所有依賴於它的觀察者物件,並在它自身的狀態改變時主動通知觀察者物件。這個主動通知通常是通過呼叫各觀察者物件所提供的介面方法來實現的。觀察者模式較完美地將目標物件與觀察者物件解耦。
接下來我們來看看kvo內部的實現機制。當某個類的物件第一次被觀察時,系統就會在執行期動態地建立該類的乙個派生類(運用runtime),在這個派生類中重寫基類中任何被觀察屬性的 setter 方法。派生類在被重寫的 setter 方法實現真正的通知機制。這麼做是基於設定屬性會呼叫 setter 方法,而通過重寫就獲得了 kvo 需要的通知機制。當然前提是要通過遵循 kvo 的屬性設定方式來變更屬性值,如果僅是直接修改屬性對應的成員變數,是無法實現 kvo 的。
同時派生類還重寫了 class 方法以「欺騙」外部呼叫者它就是起初的那個類。然後系統將這個物件的 isa 指標指向這個新誕生的派生類,因此這個物件就成為該派生類的物件了,因而在該物件上對 setter 的呼叫就會呼叫重寫的 setter,從而啟用鍵值通知機制。此外,派生類還重寫了 dealloc 方法來釋放資源。
1. 註冊
被觀察物件呼叫名為 nskeyvalueobserverregistration 的 category 方法將觀察者物件與被觀察者物件註冊與解除註冊
- (void)addobserver:(nsobject *)observer forkeypath:(nsstring *)keypath options:(nskeyvalueobservingoptions)options context:(void *)context;
- (void)removeobserver:(nsobject *)observer forkeypath:(nsstring *)keypath;
這兩個方法的定義在 foundation/nskeyvalueobserving.h 中,nsobject,nsarray,nsset均實現了以上方法,因此我們不僅可以觀察普通物件,還可以觀察陣列或集合類物件。
2. 設定屬性
將觀察者與被觀察者註冊好之後,就可以對觀察者物件的屬性進行操作,這些變更操作就會被通知給觀察者物件。注意,只有遵循 kvo 方式來設定屬性,觀察者物件才會獲取通知,也就是說遵循使用屬性的 setter 方法,或通過 key-path 來設定:
[target setage:30];
[target setvalue:[nsnumber numberwithint:30] forkey:@"age"];
3. 處理變更通知
觀察者需要實現名為 nskeyvalueobserving 的 category 方法來處理收到的變更通知:
- (void)observevalueforkeypath:(nsstring *)keypath ofobject:(id)object change:(nsdictionary *)change context:(void *)context;
在這裡,change 這個字典儲存了變更資訊,具體是哪些資訊取決於註冊時的 nskeyvalueobservingoptions。
觀察者類:
// observer.h
@inte***ce
observer : nsobject
@end
// observer.m
#import "observer.h"
#import
#import "target.h"
@implementation
observer
- (void) observevalueforkeypath:(nsstring *)keypath
ofobject:(id)object
change:(nsdictionary *)change
context:(void *)context
else
}@end
注意:在實現處理變更通知方法 observevalueforkeypath 時,要將不能處理的 key **給 super 的 observevalueforkeypath 來處理。
使用示例:
observer * observer = [[[observer alloc] init] autorelease];
target * target = [[[target alloc] init] autorelease];
[target addobserver:observer
forkeypath:@"age"
options:nskeyvalueobservingoptionnew | nskeyvalueobservingoptionold
context:[target class]];
[target setage:30];
//[target setvalue:[nsnumber numberwithint:30] forkey:@"age"];
[target removeobserver:observer forkeypath:@"age"];
在這裡 observer 觀察 target 的 age 屬性變化,執行結果如下:
>> class: target, age changed
old age is
10new age is
30
KVC KVO原理及應用 上
本文參考部落格未盡之處可到原部落格中查詢 一 kvc的原理 kvc運用了乙個isa swizzling技術,並且通過isa swizzling來實現其內部查詢定位的。簡單講 在編譯時kvc會被進行如下編譯 編譯前 obj setvalue objname forkey name 編譯後 sel se...
KVC, KVO 實現原理
方法呼叫 物件屬性 類似 person name setvalue forkey 物件的屬性或者 屬性的屬性.可見它已經包含前者.類似 person car name setvalue forkeypath kvc運用了乙個isa swizzling技術.isa swizzling就是型別混合指標機...
KVC, KVO實現原理
key value coding kvc顧名思義就是鍵值編碼,通過 setvalue value forkey key 來新增一組物件,編譯器會把這行 處理為sel sel sel get uid setvalue forkey imp method objc msg lookup site isa...