KVC搜尋規則

想想還是算了發表於2018-09-25

搜尋規則

KVC在通過key或者keyPath進行操作的時候,可以查詢屬性方法、成員變數等,查詢的時候可以相容多種命名。具體的查詢規則要以官方文件為主,所以我把官方文件翻譯了一下寫在下面。
在KVC的實現中,依賴setter和getter的方法實現,所以方法命名應該符合蘋果要求的規範,否則會導致KVC失敗
在學習KVC的搜尋規則前,要先弄明白一個屬性的作用,這個屬性在搜尋過程中起到很重要的作用。這個屬性表示是否允許讀取例項變數的值,如果為YES則在KVC查詢的過程中,從記憶體中讀取屬性例項變數的值。

@property (class, readonly) BOOL accessInstanceVariablesDirectly;
複製程式碼

基礎Getter搜尋模式
1.這是valueForKey:的預設實現,給定一個key當做輸入引數,開始下面的步驟,在這個接收valueForKey:方法呼叫的類內部進行操作.
通過getter方法搜尋例項,例如get,is,的拼接方案。按照這個順序,如果發現符合的方法,就呼叫對應的方法並拿著結果跳轉到第五步。否則,就繼續到下一步。
2.如果沒有找到簡單的getter方法,則搜尋其匹配模式的方法countOf、objectInAtIndex:、AtIndexes:。 如果找到其中的第一個和其他兩個中的一個,則建立一個集合代理物件,該物件響應所有NSArray的方法並返回該物件。否則,繼續到第三步。
代理物件隨後將NSArray接收到的countOf、objectInAtIndex:、AtIndexes:的訊息給符合KVC規則的呼叫方。
當代理物件和KVC呼叫方通過上面方法一起工作時,就會允許其行為類似於NSArray一樣。
3.如果沒有找到NSArray簡單存取方法,或者NSArray存取方法組。則查詢有沒有countOf、enumeratorOf、memberOf:命名的方法.
如果找到三個方法,則建立一個集合代理物件,該物件響應所有NSSet方法並返回。否則,繼續執行第四步.
此代理物件隨後轉換countOf、enumeratorOf、memberOf:方法呼叫到建立它的物件上。實際上,這個代理物件和NSSet一起工作,使得其表象上看起來是NSSet。
4.如果沒有發現簡單getter方法,或集合存取方法組,以及接收類方法accessInstanceVariablesDirectly是返回YES的。搜尋一個名為
、_is、、is的例項,根據他們的順序。
如果發現對應的例項,則立刻獲得例項可用的值並跳轉到第五步,否則,跳轉到第六步。
5.如果取回的是一個物件指標,則直接返回這個結果.
如果取回的是一個基礎資料型別,但是這個基礎資料型別是被NSNumber支援的,則儲存為NSNumber並返回.
如果取回的是一個不支援NSNumber的基礎資料型別,則通過NSValue進行儲存並返回.
6.如果所有情況都失敗,則呼叫valueForUndefinedKey:方法並丟擲異常,這是預設行為。但是子類可以重寫此方法.

基礎Setter搜尋模式
這是setValue:forKey:的預設實現,給定輸入引數value和key。試圖在接收呼叫物件的內部,設定屬性名為key的value,通過下面的步驟:
1.查詢set:或_set命名的setter,按照這個順序,如果找到的話,呼叫這個方法並將值傳進去(根據需要進行物件轉換)。
2.如果沒有發現一個簡單的setter,但是accessInstanceVariablesDirectly類屬性返回YES,則查詢一個命名規則為_、_is、is的例項變數。根據這個順序,如果發現則將value賦值給例項變數。
3.如果沒有發現setter或例項變數,則呼叫setValue:forUndefinedKey:方法,並預設提出一個異常,但是一個NSObject的子類可以提出合適的行為。
NSMutableArray搜尋模式
這是mutableArrayValueForKey:的預設實現,給一個key當做輸入引數。在接收訪問器呼叫的物件中,返回一個名為key的可變代理陣列,這個代理陣列就是用來響應外界KVO的物件,通過下面的步驟進行查詢:
1.查詢一對方法insertObject:inAtIndex:和removeObjectFromAtIndex:(相當於NSMutableArray的原始方法insertObject:atIndex:和removeObjectAtIndex:)或者方法名是insert:atIndexes:和removeAtIndexes:(相當於NSMutableArray的原始方法insertObjects:atIndexes:和removeObjectsAtIndexes:)。

如果找到最少一個insert方法和最少一個remove方法,則返回一個代理物件,來響應傳送給NSMutableArray的組合訊息insertObject:inAtIndex:、removeObjectFromAtIndex:、insert:atIndexes:,和removeAtIndexes:訊息。
當物件接收一個mutableArrayValueForKey:訊息並實現可選替換方法,例如replaceObjectInAtIndex:withObject:或replaceAtIndexes:with:方法,代理物件會在適當的情況下使用它們,以獲得最佳效能。

2.如果物件沒有可變陣列方法,查詢一個替代方法,命名格式為set:。在這種情況下,向mutableArrayValueForKey:的原始響應者傳送一個set:訊息,來返回一個代理物件來響應NSMutableArray事件。
提示:
這一步描述的機制遠不如上一步有效,因為它可能重複建立新的集合物件,而不是修改現有的物件。因此,在自己設計的KVC時應該儘量避免它。

3.如果沒有可變陣列的方法,也沒有找到訪問器,但接受響應的類accessInstanceVariablesDirectly屬性返回YES,則查詢一個名為_或的例項變數。
按照這個順序,如果找到例項變數,則返回一個代理物件。改物件將接收所有NSMutableArray傳送過來的訊息,通常是NSMutableArray或其子類。

4.如果所有情況都失敗,則返回一個可變的集合代理物件。當它接收NSMutableArray訊息時,傳送一個setValue:forUndefinedKey:訊息給接收mutableArrayValueForKey:訊息的原始物件。
這個setValue:forUndefinedKey:的預設實現是提出一個NSUndefinedKeyException異常,但是子類可以重寫這個實現。

相關文章