天天看點

深入了解 KVC\KVO 實作機制 — KVC

介紹iOS開發中常用的KVC的核心機制

KVC和KVO都屬于鍵值程式設計而且底層實作機制都是isa-swizzing,是以本來想放在一起講的。但是篇幅有限是以就分成了兩篇博文 KVO實作機制傳送門

KVC概述

  • KVC是Key Value Coding的簡稱。它是一種可以通過字元串的名字(key)來通路類屬性的機制。而不是通過調用Setter、Getter方法通路。
  • 關鍵方法定義在 NSKeyValueCodingProtocol
  • KVC支援類對象和内建基本資料類型。

KVC使用

  • 擷取值

    valueForKey: 傳入NSString屬性的名字。

    valueForKeyPath: 屬性的路徑,xx.xx

    valueForUndefinedKey 預設實作是抛出異常,可重寫這個函數做錯誤處理

  • 修改值

    setValue:forKey:

    setValue:forKeyPath:

    setValue:forUnderfinedKey:

    setNilValueForKey: 對非類對象屬性設定nil時調用,預設抛出異常。

KVC鍵值查找

搜尋單值成員
  • setValue:forKey:搜尋方式

1、首先搜尋setKey:方法。(key指成員變量名,首字母大寫)

2、上面的setter方法沒找到,如果類方法accessInstanceVariablesDirectly傳回YES。那麼按 _key,_isKey,key,iskey的順序搜尋成員名。(NSKeyValueCodingCatogery中實作的類方法,預設實作為傳回YES)

3、如果沒有找到成員變量,調用setValue:forUnderfinedKey:

  • valueForKey:的搜尋方式

1、首先按getKey,key,isKey的順序查找getter方法,找到直接調用。如果是BOOL、int等内建值類型,會做NSNumber的轉換。

2、上面的getter沒找到,查找countOfKey、objectInKeyAtindex、KeyAtindexes格式的方法。如果countOfKey和另外兩個方法中的一個找到,那麼就會傳回一個可以響應NSArray所有方法的代理集合的NSArray消息方法。

3、還沒找到,查找countOfKey、enumeratorOfKey、memberOfKey格式的方法。如果這三個方法都找到,那麼就傳回一個可以響應NSSet所有方法的代理集合。

4、還是沒找到,如果類方法accessInstanceVariablesDirectly傳回YES。那麼按 _key,_isKey,key,iskey的順序搜尋成員名。

5、再沒找到,調用valueForUndefinedKey。

KVC實作分析

KVC運用了isa-swizzing技術。isa-swizzing就是類型混合指針機制。KVC通過isa-swizzing實作其内部查找定位。isa指針(is kind of 的意思)指向維護分發表的對象的類,該分發表實際上包含了指向實作類中的方法的指針和其他資料。

比如說如下的一行KVC代碼:

[site setValue:@"sitename" forKey:@"name"];

//會被編譯器處理成

SEL sel = sel_get_uid(setValue:forKey);
IMP method = objc_msg_loopup(site->isa,sel);
method(site,sel,@"sitename",@"name");
           

每個類都有一張方法表,是一個hash表,值是還書指針IMP,SEL的名稱就是查表時所用的鍵。

SEL資料類型:查找方法表時所用的鍵。定義成char*,實質上可以了解成int值。

IMP資料類型:他其實就是一個編譯器内部實作時候的函數指針。當Objective-C編譯器去處理實作一個方法的時候,就會指向一個IMP對象,這個對象是C語言表述的類型。

KVC的内部機制:

一個對象在調用setValue的時候進行了如下操作:

  • (1)根據方法名找到運作方法的時候需要的環境參數
  • (2)他會從自己的isa指針結合環境參數,找到具體的方法實作接口。
  • (3)再直接查找得來的具體的實作方法