KVO與KVC原理筆記

派二星發表於2019-04-08

KVO的實現原理

當我們對A類新增監聽的時候,系統會自動生成一個NSKVONotifying_A的子類,這個類重寫了A的class、superclass、deealloc方法和該屬性的Set方法,同時A類的物件的isa指標指向了該虛擬子類。當監聽屬性改變的時候系統呼叫NSSetobjectValueandNotify,這個方法的執行流程是(willchangeValueforkey->改變父類的值->didchangeValueforkey->observeValueForKey:ofObject:change:context:),如果設定automaticallyNotifiesObserversForKey:(NSString *)key為NO的時候則需要手動觸發KVO即手動呼叫willchangeValueforkey和didchangeValueforkey.

func _NSSetObjectValueAndNotify {
    ...
    willchangeValueforkey
    ...
    "
    objc_msgSendSupper '改變父類的值(猜測這樣實現)
    "
    ...
    didchangeValueforkey
    ...
    observeValueForKey:ofObject:change:context: 
}

複製程式碼

Q1: 為什麼重寫系統的class/superclass、deealloc方法

因為該子類為系統自動生成蘋果想偽裝成並沒有這個類 所以重寫class/superclass ,但是呼叫 objc_getClass()這個方法時候依然會暴露,因為這個方法是呼叫呼叫物件的isa指標指向。dealloc則是系統還有一些其他的事情處理

Q2:為什麼KVO要實現一個子類

KVC是什麼,他是如何實現的

KVCKVC是由NSKeyValueCoding非正式協議實現的一種機制,物件採用該協議來提供對其屬性的間接訪問。當一個物件符合鍵值編碼時,它的屬性可以通過一個簡潔、統一的訊息傳遞介面通過字串引數來定址。這種間接訪問機制補充了例項變數及其關聯的訪問方法所提供的直接訪問。

valueForkey的查詢流程

  1. 在例項中搜尋找到的類裡面的相關方法,其名稱依次為get<Key>, <key>, is<Key>, or _<key>。如果找到,則呼叫它,並繼續執行步驟5的結果。否則繼續下一步。
  2. 如果沒有找到那麼搜尋countOf<Key> and objectIn<Key>AtIndex:,如果找到了其中的第一個和另外兩個中的至少一個,則建立一個collection代理物件,該物件響應所有NSarray方法並返回該物件, 如果沒有找到陣列相關方法那麼搜尋countOf<Key>, enumeratorOf<Key>, and memberOf<Key>:,如果實現了其中一個則該物件響應所有Set方法的,
  3. 如果上述方法都沒有找到那麼判斷accessInstanceVariablesDirectly 屬性是否為yes,如果為yes則查詢**_<key>, _is<Key>, <key>, or is<Key>**屬性,如果找到直接返回變數值
  4. 如果都沒找到那麼且accessInstanceVariablesDirectly為false,那麼執行valueForUndefinedKey:方法,呼叫valueForUndefinedKey:,預設情況下,這會引發異常,但NSObject的子類可能提供關鍵的特定行為

setValueForkey的實現

set value:for key:的預設實現:給定key和value引數作為輸入,嘗試在接收呼叫的物件內,使用以下過程將名為key的屬性設定為value(對於非物件屬性,則設定未包裝的value版本,如表示非物件值:

  1. 按此順序查詢名為set<key> 和 **_set<key>**的第方法。如果找到了,使用value值呼叫它並完成。
  2. 如果找不到簡單訪問器,並且類方法accessInstanceVariablesDirectly返回Yes,則按該順序查詢名為 _<key>、_is<key>、<key>或is<key>的例項變數。如果找到,直接用value設定。
  3. 在找不到方法或例項變數時,呼叫setValue:ForUndefinedKey:。預設情況下,這會引發異常,但NSObject的子類可能提供關鍵的特定行為。

相關文章