Key-Value Observing (簡寫為KVO):當指定的對象的屬性被修改了,允許對象接受到通知的機制。每次指定的被觀察對象的屬性被修改的時候,KVO都會自動的去通知相應的觀察者,相當於設計模式中的觀察者模式。
KVO的優點:
當有屬性改變,KVO會提供自動的訊息通知。這樣的架構有很多好處。首先,開發人員不需要自己去實現這樣的方案:每次屬性改變了就發送訊息通知。這是KVO 機制提供的最大的優點。因為這個方案已經被明確定義,獲得架構級支援,可以方便地採用。開發人員不需要添加任何代碼,不需要設計自己的觀察者模型,直接可 以在工程裡使用。其次,KVO的架構非常的強大,可以很容易的支援多個觀察者觀察同一個屬性,以及相關的值。
下面我們寫個簡單的demo,如何使用KVO
首先定義一個類,聲明兩個屬性,name跟pid;
@interface DataModel : NSObject{ NSString *name; NSString *pid; }
在controller裡
- (void)viewDidLoad{ [super viewDidLoad]; dm=[[DataModel alloc] init]; [dm setValue:@"daren" forKey:@"name"]; [dm setValue:@"1" forKey:@"pid"]; //註冊成為觀察者 選項參數指定了發送變更通知時提供給觀察者的資訊。使用NSKeyValueObservingOptionOld選項可以將初始對象值以變更字典中的一個項的形式提供給觀察者。指定NSKeyValueObservingOptionNew選項可以將新的值以一個項的形式添加至變更字典。 [dm addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil]; testLabel=[[UILabel alloc] init]; [testLabel setFrame:CGRectMake(20, 20, 100, 30)]; [testLabel setBackgroundColor:[UIColor clearColor]]; [testLabel setTintColor:[UIColor blackColor]]; [testLabel setText:[dm valueForKey:@"name"]]; [self.view addSubview:testLabel]; UIButton *testButton=[UIButton buttonWithType:UIButtonTypeRoundedRect]; [testButton setFrame:CGRectMake(20, 100, 100, 70)]; [testButton setTitle:@"測試" forState:UIControlStateNormal]; [testButton addTarget:self action:@selector(testPressed:) forControlEvents:UIControlEventTouchUpInside]; [self.view addSubview:testButton]; }-(void) testPressed:(id) sender{ [dm setValue:@"wangzi" forKey:@"name"]; }-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if([keyPath isEqualToString:@"name"]) { testLabel.text = (NSString *)[dm valueForKey:@"name"]; }}- (void)dealloc{ [testLabel release]; [dm removeObserver:self forKeyPath:@"name"]; [dm release]; [super dealloc]; }
上述代碼中,我們設定了label的文字會隨著datamodel類中的一個key的值變化而變化,這就是KVO的一個簡單的運用。但KVO是基於KVC實現的,那什麼又是KVC。
KVC:Key-Value Coding,直譯是:索引值編碼。簡單來講,就是給屬性設定值的;複雜來講,根據網上的說法,KVC運用了一個isa-swizzling技術。isa-swizzling就是類型混合指標機制。KVC主要通過isa-swizzling,來實現其內部尋找定位的。isa指標,如其名稱所指,(就是is a kind of的意思),指向維護分發表的對象的類。該分發表實際上包含了指向實作類別中的方法的指標,和其它資料。
比如說如下的第一行KVC的代碼,其實和第二行的普通代碼是等效的:
[myClass setValue:@"daren" forKey:@"name"];
myClass._name = @"daren";
KVC的代碼會被編譯器處理成:
SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (myClass->isa,sel);
method(site, sel, @"daren", @"name");
這下KVC內部的實現就很清楚的清楚了:一個對象在調用setValue的時候:
a. 首先根據方法名找到運行方法的時候所需要的環境參數。
b. 它會從自己isa指標結合環境參數,找到具體的方法實現的介面。
c. 再直接尋找得來的具體的方法實現。
和notification的區別也是在,KVO是對象之間直接的互動,而notification需要notificationCenter來做為中間互動。 以上都是一些比較淺的理解,更深層次的原理,還需要大家來補充~~~~