iOS KVC KVO 關係及原理

2021-10-04 08:09:14 字數 2628 閱讀 8707

在很多時候接觸到很多地方都有對 kvc,kvo 的描述,但是都是一筆帶過。只知道這是 object-c 提供的乙個不錯的機制,可以很好的減少**。

首先我們先了解下

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 運用了乙個 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");

其中:

kvc 在呼叫方法 setvalue 的時候:

首先根據方法名找到執行方法的時候所需要的環境引數。

他會從自己 isa 指標結合環境引數,找到具體的方法實現的介面。

再直接查詢得來的具體的方法實現。

這樣的話前面介紹的 kvo 實現就好理解了

當乙個物件註冊了乙個觀察者,被觀察物件的 isa 指標被修改的時候,isa 指標就會指向乙個中間類,而不是真實的類。

所以 isa 指標其實不需要指向例項物件真實的類。所以我們的程式最好不要依賴於 isa 指標。在呼叫類的方法的時候,最好要明

確物件例項的類名。

這樣只有當我們呼叫 kvc 去訪問 key 值的時候 kvo 才會起作用。所以肯定確定的是,kvo 是基於 kvc 實現的。

下面例項演示一下:

@implementation person

@synthesize name,age; // 屬性 name 將被監視

-(void)changename

@end

@implementation personmonitor

- (void)observevalueforkeypath:(nsstring *)keypath ofobject:(id)object change:(nsdictionary *)change context:(void *)context

}@end

// 測試**

person *p = [[person alloc] init]; // 監視物件

personmonitor *pm = [[personmonitor alloc]init];

[p addobserver:pm forkeypath:@"name" options:(nskeyvalueobservingoptionnew | nskeyvalueobservingoptionold) context:nil];

// 測試前的資料

nslog(@"p.name is %@",p.name);

// 通過 setvalue 的方法,personmonitor 的監視將被呼叫

[p setvalue:@"name kvc" forkey:@"name"];

// 檢視設定後的值

nslog(@"p name get by kvc is %@",[p valueforkey:@"name"]);

// 效果和通過 setvalue 是一致的

p.name=@"name change by .name=";

// 通過 person 自己的函式來更改 name

[p changename]; 

// 最後一次修改是直接修改,所以沒法產生通知。

組成原理 記憶體及記憶體與CPU的關係

首先,我們對計算機的記憶體進行簡單的了解 記憶體 memory 又稱內部儲存器,是計算機的重要組成部分。其主要作用是進行程式的執行和程式執行過程中一些半成品資料的儲存。根據不同的效能,有以下幾類內部儲存器 唯讀儲存器 rom read only memory rom,唯讀儲存器,在製造rom的時候,...

關係型資料庫鎖表原理及解決方法

鎖表原理 1 鎖表發生在insert update delete 中 2 鎖表的原理是 資料庫使用獨佔式封鎖機制,當執行上面的語句時,對錶進行鎖住,直到發生commite 或者 回滾 或者退出資料庫使用者 3 鎖表的原因 第一 a程式執行了對 tablea 的 insert 並還未 commit時,...

關係型資料庫原理

這篇文章是對知乎上如何自己實現乙個關係型資料庫的乙個嘗試性回答,後續會不斷更新。對外資料模型為關係型資料庫,內部的實現主要分成兩大類,一類是disk based,比如mysql,postgres,一類是memory based,後者包括memsql,sap haha,oceanbase。這裡說乙個d...