KVO/KVC原理

KVC/KVO原理

KVC

KVC訪問屬性時儘可能嘗試使用存取方法,當KVC訪問屬性時,它內部其實做了很多事:

以一個屬性icon爲例

  1. 首先查找模型中有沒有setIcon方法,如果有有,直接調用[self setIcon:dict[@"icon"]];
  2. 如果找不到set方法,直接尋找有沒有icon屬性,如果有,就直接訪問模型中icon = dict[@"icon"];
  3. 如果找不到icon屬性,就尋找_icon屬性,如果有,直接_icon = dict[@"icon"]
  4. 如果都找不到,就會報錯
    [<Flag 0x7xxxxx> setValue:forUndefinedKey:]

當然,KVC提供了鍵值檢測機制(KVV)

- (BOOL)validateValue:(inout id *)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;  

當然,這個方法是需要手動調用的,並不會自動調用,KVC的實現原理還是比較簡單的,這裏重點是要說明一下KVO

KVO

當某個類的對象第一次被觀察時,系統就會在運行期動態地創建該類的一個派生類,在這個派生類中重寫基類中被觀察屬性的 setter 方法,在setter方法裏使其具有通知機制。因此,要想KVO生效,必須直接或間接的通過setter方法訪問屬性(KVC的setValue就是間接方式)。直接訪問成員變量KVO是不生效的。

同時派生類還重寫了 class 方法以“欺騙”外部調用者它就是起初的那個類。然後系統將這個對象的 isa 指針指向這個新誕生的派生類,因此這個對象就成爲該派生類的對象了,因而在該對象上對 setter 的調用就會調用重寫的 setter,從而激活鍵值通知機制。此外,派生類還重寫了 dealloc 方法來釋放資源。

舉個?

比如,我們要對一個Dog做一個監測,那麼,runtime就會創建一個名爲NSKVONotifying_Dog

新的NSKVONotifying_Dog類會重寫一下方法:
增加了監聽屬性對應的set,class,dealloc,_isKVOA

  1. class

    重寫class方法是爲了我們調用它的時候返回跟重寫繼承類之前同樣的內容。

    打印如下內容:

    NSLog(@"self->isa:%@",self->isa);  
    NSLog(@"self class:%@",[self class]);  

    在建立KVO監聽之前,打印的結果爲:

    self->isa:Dog 
    self class:Dog  
    

    在建立監聽之後,打印的結果爲:

    objective-c
    self->isa:NSKVONotifying_Dog
    self class:Dog

  2. set

    重寫set方法,是爲了在set方法中增加另外兩個方法的調用:

    - (void)willChangeValueForKey:(NSString *)key  
    - (void)didChangeValueForKey:(NSString *)key

    其中,didChangeValueForKey負責調用:

    
    - (void)observeValueForKeyPath:(NSString *)keyPath  
                         ofObject:(id)object  
                           change:(NSDictionary *)change  
                          context:(void *)context  

    這個就是你在監聽中寫的回調函數,這樣就實現了KVO,這裏有幾點需要注意的東西:

如果沒有任何的訪問器方法,-setValue:forKey方法會直接調用:


- (void)willChangeValueForKey:(NSString *)key  
- (void)didChangeValueForKey:(NSString *)key  

比如說我們沒有自動生成setter 和 getter 方法,我們只是通過下劃線命名了 _icon,那麼,我們只要手動調用這兩個方法,也會實現鍵值監聽

  1. _isKVOA

    這個私有方法應該是用來標識該類是一個 KVO 機制聲稱的類,不去關心

到此,一個KVO/KVC的基本實現就是這麼多了

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