KVO、KVC的實現原理與應用

KVOKVC的實現原理與應用

各種名詞:
KVO : key value observing
KVC : key value Coding

KVO 是什麼

KVOOC觀察者設計模式的一種實現方式,是以非正式協議(Category)的形式定義在NSObject中。
當一個被觀察的對象(如類A)的某個屬性放生改變時,對象會獲得通知,並作出了相應的處理。
MVC設計架構下,KVO是一種理想的ModelView之間的通訊機制。例如,在控制器中創建ModelA的觀察者,當ModelA的某個屬性發生變化時,可以通過KVO使得控制器收到通知,並作出變化。

KVO的實現原理

舉個栗子,當觀察對象類ClassApropertyX時,KVO機制會動態的創建ClassA的子類,並且爲這個新的子類重現被觀察的屬性propertyXkeyPathsetter方法。當propertyX發生改變時,會調用setter方法,這時候,setter做了一件事情,那就是通知觀察者該屬性改變的狀態。

那麼,iOS 是如何動態創建ClassA的呢?
Apple使用了isa-swizzling來實現KVO的動態創建。當觀察ClassA時,KVO會動態的創建一個新的 名爲NSKVONotifying_ClassA類,並重寫了setter方法,該方法會負責在調用原setter方法之前和之後通知所有觀察對象屬性值的更改情況。

  1. NSNotifying_ClassA類:在這個過程中,被觀察的isa指針(即Runtime中指向對象的類的指針)從指向的是原來的ClassA類,被KVO機制修改爲指向NSNotifying_ClassA,用來實現當前類的屬性值改變監聽。
    當我們手動的創建了NSNotifying_ClassA類,那麼就會使得系統運行到註冊KVO的那段代碼時崩潰。
  2. 子類的setter方法剖析:查看NSObject的兩個方法willChangeValueForKey:didChangevlueForKey:,在存取數值的前後分別會調用這兩個方法,分別在屬性改變前和改變後進行調用。
    KVO爲子類的觀察者屬性重寫調用存取方法的工作原理在代碼中相當於:
-(void)setName:(NSString *)newName{ 
    [self willChangeValueForKey:@"name"];    //KVO在調用存取方法之前總調用 
    [super setValue:newName forKey:@"name"]; //調用父類的存取方法 
    [self didChangeValueForKey:@"name"];     //KVO在調用存取方法之後總調用
}

觀察者觀察的是屬性,只有遵循了KVO變更屬性值的方式纔會執行KVO的回調方法,例如是否執行了setter方法、或者是否使用了KVC賦值。
如果賦值的方式沒有通過setter方法,那麼就只是改變值,不會發出通知。例如,以下方式不會觸發KVO機制。

_name = @"newName";

KVO實現步驟

  1. 註冊觀察者,實施監聽
//第一個參數observer:觀察者 (這裏觀察self.myKVO對象的屬性變化)
//第二個參數keyPath: 被觀察的屬性名稱(這裏觀察self.myKVO中num屬性值的改變)
//第三個參數options: 觀察屬性的新值、舊值等的一些配置(枚舉值,可以根據需要設置,例如這裏可以使用兩項)
//第四個參數context: 上下文,可以爲kvo的回調方法傳值(例如設定爲一個放置數據的字典)
[self.myKVO addObserver:self forKeyPath:@"num" options:
NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
  1. 在回調方法中處理屬性發生的變化
    當屬性(keyPath)的值發生變化時,收到通知,調用以下方法:
// keyPath:屬性名稱
// object:被觀察的對象
// change:變化前後的值都存儲在change字典中
// context:註冊觀察者時,context傳過來的值
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
{
}
  1. 移除觀察者

KVCKVO的不同

KVC是一個非正式的Protocol,使用字符串訪問一個對象實例變量的機制。而不是通過settergetter方法等顯式的存取方式去訪問。例如,在動畫中,可以使用KVC的方式改變view的參數。
KVO是一種機制,當制定的對象屬性被修改後,對象就會接受到通知。

KVOnotification的不同

兩者都是一對多,但是對象之間直接的交互,notification明顯得多,需要一箇中間交互NSNotificationCenter

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章