KVC & KVO原理

1、KVC

KVC可以通過key直接訪問對象的屬性,或者給獨享的屬性直接賦值,這樣可以在運行時動態(tài)的訪問或修改對象的屬性。

當調(diào)用setValue:forKey: setValue:forKeyPath:時,底層的執(zhí)行機制如下:

1. 程序首先按照`setKey:`、`_setKey:`、`setIsKey:`順序查找方法,如果找到直接調(diào)用該方法,結束。

2. 如果沒有找到,????????????????則會查看`+(BOOL)accessInstanceVariablesDirectly`方法的返回值:
    2.1. 如果返回`NO`,表示不允許訪問成員變量,則直接執(zhí)行`setValue:forUndefinedKey:`方法拋出異常,結束。
    2.2. 如果返回`YES`,表示允許訪問成員變量。

3. 如果允許訪問成員變量,則按照 `_key`、`_isKey`、`key`、`isKey` 的順序查找成員變量,如果找到了成員變量,則直接賦值,結束。

4. 如果沒有仍然沒有找到成員變量,則直接執(zhí)行`setValue:forUndefinedKey:`方法拋出異常,結束。

當調(diào)用valueForKey:valueForKeyPath:時,底層的執(zhí)行機制如下:

1. 程序首先按照`getKey`、`key`、`isKey`、`_getKey`、`_key`順序查找方法,如果找到直接調(diào)用該方法,結束。

2. 如果沒有仍然沒有找到以上方法,則會調(diào)用一些動態(tài)生成的集合方法(這些方法可以可重新定義KVC的一些功能):
    2.1. 如果同時存在`countOf<Key>`和[`objectIn<Key>AtIndex:` `<Key>AtIndexes:`]中的一個方法,
         則返回一個可以響應NSArray所有方法的代理集合
         還有一個可選方法 `get<Key>:range:`
    2.2. 如果同時存在 `countOf<Key>`,`enumeratorOf<Key>`,`memberOf<Key>:` 三個方法,
         則返回一個可以響應NSSet所有方法的代理集合

3. 如果沒有找到,????????????????則會查看`+(BOOL)accessInstanceVariablesDirectly`方法的返回值:
    3.1. 如果返回`NO`,表示不允許訪問成員變量,則直接執(zhí)行`valueForUndefinedKey`方法拋出異常,結束。
    3.2. 如果返回`YES`,表示允許訪問成員變量。

4. 如果允許訪問成員變量,則按照`_key`、`_isKey`、`key`、`isKey`的順序查找成員變量,如果找到了成員變量,則直接賦值,結束。

5. 如果沒有仍然沒有找到成員變量,則直接執(zhí)行`valueForUndefinedKey:`方法拋出異常,結束。

2、KVO

KVO全稱KeyValueObserving,是蘋果提供的一套事件通知機制。允許對象監(jiān)聽另一個對象特定屬性的改變,并在改變時接收到事件。由于KVO的實現(xiàn)機制,所以對屬性才會發(fā)生作用,一般繼承自NSObject的對象都默認支持KVO

實現(xiàn)原理

  • KVO是通過isa-swizzling技術實現(xiàn)的。
  • 在運行時根據(jù)原類創(chuàng)建一個中間類NSKVONotifying_KVOObject,這個中間類是原類的子類,并動態(tài)修改當前對象的isa指向中間類。并且將class方法重寫,返回原類的Class。
  • 重寫被監(jiān)聽屬性的setter方法:在重寫的setter方法中,修改值之前會調(diào)用willChangeValueForKey:方法,修改值之后會調(diào)用didChangeValueForKey:方法,這兩個方法最終都會被調(diào)用到observeValueForKeyPath:ofObject:change:context:方法中

面試題

1、使用KVC設值能觸發(fā)KVO嗎?直接修改成員變量呢?

會觸發(fā)KVO,KVC內(nèi)部會調(diào)用 `willChangeValueForKey:` 和 `didChangeValueForKey:` 方法
直接修改修改成員變量不會觸發(fā) KVO

2、iOS用什么方式實現(xiàn)對一個對象的KVO?(KVO的本質是什么?)

當一個對象使用了KVO監(jiān)聽,iOS系統(tǒng)會修改這個對象的isa指針,改為指向一個全新的通過Runtime動態(tài)創(chuàng)建的子類
子類擁有自己的set方法實現(xiàn),內(nèi)部會調(diào)用
willChangeValueForKey:
原來的setter
didChangeValueForKey:, 這個方法的內(nèi)部又會調(diào)用監(jiān)聽器observer的方法

3、如何手動出發(fā)KVO?

手動調(diào)用這兩個方法,必須兩個方法同時有
willChangeValueForKey:
didChangeValueForKey:
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

友情鏈接更多精彩內(nèi)容