Key-Value Coding Programming Guide 官方文件第二部分第6節 2018.9.20 第一次修正
Key-Value Coding Fundamatals--Accessor Search Patterns
##訪問器搜尋方式
NSObject預設實現NSKeyValueCoding協議提供的基於鍵的訪問器,使用一組明確定義的規則來呼叫物件的基礎屬性。這些協議方法使用鍵引數在其自己的物件例項中搜尋訪問器,例項變數以及遵循某些命名約定的相關方法。儘管您很少修改此預設搜尋, 但瞭解它的工作方式會有所幫助,對於跟蹤鍵值編碼物件的行為,也可以使您自己的物件相容。
注意 本節中的描述使用
<key>
或<Key>
作為鍵字串的佔位符,該鍵字串在一個鍵值編碼協議方法中作為引數出現,然後該方法將該鍵字串用作間接方法呼叫或變數名稱查詢的一部分。對映的屬性名稱遵循佔位符大小寫的情況。例如,對於getter<key>
和is<KEY >
,名為hidden
的屬性對映為hidden
和isHidden
.。
基本的Getter搜尋模式
valueForKey:
的預設實現,給定一個key
引數作為輸入,在接收valueForKey:
呼叫的類例項中操作,執行以下過程。
1.搜尋例項與名稱,按照該順序,搜尋找到的名稱為get<Key>
、<key>
、is<Key>
或<key>
的第一個訪問器方法。如果找到,呼叫它並繼續到步驟5。否則請繼續執行下一步。
2.如果找不到簡單取值方法, 則在例項中搜尋其方法名形如 countOf<Key>
和objectIn<Key>AtIndex:
(相當於NSArray
類中定義的基本方法)和<key>AtIndexes
:(相當於NSArray
類中的objectsAtIndexes:
方法)的方法。
如果第一個方法和後邊兩個方法中的至少一個方法被實現了, 則建立一個能夠響應所有NSArray
方法並返回該方法的集合代理物件。否則, 繼續執行步驟3。
代理物件隨後將它接收的任何NSArray訊息轉換為countOf <Key>
,objectIn <Key> AtIndex:
和<key> AtIndexes:
的訊息,並將其傳送給建立它的鍵值編碼相容物件。如果原始物件還實現了一個名為get <Key>:range:
的可選方法,則代理物件也會在適當時使用該方法。實際上,與符合鍵值編碼的物件一起工作的代理物件允許底層屬性的行為就像它是一樣NSArray
,即使它不是。
3.如果沒有找到簡單的訪問器方法或陣列訪問方法組,請查詢名為countOf <Key>
,enumeratorOf <Key>
和memberOf <Key>:
的方法的三個方法(對應於NSSet
類定義的原始方法)。
如果找到所有三個方法,請建立一個響應所有NSSet
方法並返回該方法的集合代理物件。 否則,請繼續執行步驟4。
這個代理物件隨後將它接收的任何NSSet
訊息轉換為count Of <Key>
,enumeration of <Key>
和member Of <Key>:
訊息到建立它的物件。實際上,與符合鍵值編碼的物件一起工作的代理物件允許底層屬性的行為就像它是一樣NSSet
,即使它不是。
4.如果找不到簡單訪問器方法或集合訪問方法組, 並且訊息接收者的類方法accessInstanceVariablesDirectly
返回YES, 則系統按以下順序搜尋名為:_<key>
、 _is<Key>
、 <key>
或is<Key>
的例項變數。如果找到, 則直接獲取例項變數的值, 然後繼續執行步驟5。否則, 繼續跳轉到步驟6。
5.如果獲取到的屬性值是物件指標,即獲取的是物件, 則直接將物件返回。
如果獲取到的屬性值是NSNumber支援的資料型別, 則將其儲存在NSNumber例項並返回。 如果獲取到的屬性值不是 NSNumber 支援的型別, 則轉換為NSValue物件, 然後返回。
6.如果上述所有方法都沒有執行,則呼叫valueForUndefinedKey:
。 預設情況下,這會引發異常,但NSObject的子類可以通過過載並根據特定key做一些特殊處理。
基本的Setter搜尋方式
setValue:forKey:
的預設實現, 給定key
和value
引數作為輸入, 在接收呼叫的物件內嘗試將名為key的屬性設定為value(或者, 對於非物件屬性, 則為unwarp value, 詳見Representing Non-Object Values), 使用以下過程:
-
1.按照順序查詢第一個名為
set<Key>:
或_set<Key>
的方法。如果找到, 傳入輸入值 (或根據需要展開值) 呼叫它, 然後完成。 -
2.如果找不到簡單訪問器, 並且類方法
accessInstanceVariablesDirectly
返回YES, 則按以下順序查詢例項變數:_<key>
、_is<Key>
、<key>
、is<Key>
。如果找到, 則直接使用輸入值 (或展開值) 設定變數並完成。 -
3.如果找不到以上方法或例項變數, 則呼叫
setValue:forUndefinedKey:
。預設情況下,這會引發異常,但NSObject
的子類可以通過過載並根據特定key做一些特殊處理。
可變陣列的搜尋方式
mutableArrayValueForKey:
的預設實現,給定一個key
引數作為輸入,使用以下過程為接收訪問者呼叫的物件內的一個名為key
的屬性返回一個可變代理陣列:
1.查詢一對方法, 名為insertObject:in <Key> AtIndex:
和removeObjectFrom <Key> AtIndex:
的方法(分別對應於NSMutableArray
原始方法insertObject:atIndex:
和removeObjectAtIndex:
) ,或者名稱類似於insert <Key>:atIndexes:
和remove <Key> AtIndexes:
(對應於NSMutableArrayinsertObjects:atIndexes:
和removeObjectsAtIndexes:
方法)。
如果物件至少實現一個插入方法和至少一個刪除方法,則返回一個響應NSMutableArray
訊息的代理物件,方法是傳送insertObject:in <Key> AtIndex:
,removeObjectFrom <Key> AtIndex:
,insert <Key>:atIndexes:
,和remove <Key> AtIndexes:
訊息到mutableArrayValueForKey:
的原始接收者。
當接收mutableArrayValueForKey:
訊息的物件也實現了一個可選的替換物件方法,其名稱如replaceObjectIn <Key> AtIndex:withObject:
或replace <Key> AtIndexes:with <Key>:
,代理物件在適合最佳效能時會自動呼叫該可選方法。
2.如果物件沒有可變陣列方法,則查詢名稱與模式set <Key>:
匹配的訪問器方法。 在這種情況下,通過向mutableArrayValueForKey:
的原始接收者發出set <Key>:
訊息,返回響應NSMutableArray訊息的代理物件。
注意: 此步驟中描述的機制比上一步的效率要低得多, 因為它可能涉及重複建立新的集合物件, 而不是修改現有的。因此, 在設計自己的鍵值編碼相容物件時, 通常應避免這種情況。
3.如果既沒有找到可變陣列方法,也沒有找到訪問器,並且接收者的類對accessInstanceVariablesDirectly
響應'YES,則按照順序搜尋名為
_ 或
`的例項變數。
如果找到這樣的例項變數,則返回一個代理物件,該物件將它接收的每個NSMutableArray
訊息轉發給例項變數的值,該值通常是NSMutableArray
的例項或其子類之一。
4.如果所有其他方法都失敗了,只要收到NSMutableArray
訊息,就返回一個可變集合代理物件,該物件向mutableArrayValueForKey:
訊息的原始接收者發出setValue:forUndefinedKey:
訊息。
setValue:forUndefinedKey:的預設實現會丟擲NSUndefinedKeyException異常, 但子類可能會重寫此行為。
可變有序集的搜尋方式
mutableOrderedSetValueForKey的預設實現:將相同的簡單訪問器方法和有序集訪問器方法識別為valueForKey :
(請參閱 Default Search Pattern for the Basic Getter
),並遵循相同的直接訪問例項變數策略,但始終返回可變集合代理物件 valueForKey:
返回的不可變集合。 此外,它還執行以下操作:
1.搜尋名稱類似於以下形式的方法: insertObject:in <Key> AtIndex:
和removeObjectFrom <Key> AtIndex:
(對應於NSMutableOrderedSet
類定義的兩個最原始方法),以及insert <Key>: atIndexes:
和remove <Key> AtIndexes:
(對應於insertObjects:atIndexes:
和removeObjectsAtIndexes:
)。
如果找到至少一個insert方法和至少一個remove方法,返回的代理物件每次接收到 NSMutableOrderedSet的訊息後, 會通過以下組合方法給mutableOrderedSetValueForKey
的原始物件 傳送訊息: mutableOrderedSetValueForKey:
insertObject:in<Key>AtIndex:
, removeObjectFrom <Key> AtIndex :
, insert <Key>:atIndexes:
remove<Key>AtIndexes:
代理物件還使用方法名為 replaceObjectIn <Key> AtIndex:withObject:
的方法,或replace<Key>AtIndexes:with<Key>:
,當這些方法存在於原始物件中時。
2.如果找不到可變的set方法,請搜尋名為set <Key>:
的訪問器方法。 在這種情況下,返回的代理物件每次收到NSMutableOrderedSet
訊息時都會向mutableOrderedSetValueForKey:
的原始接收者傳送一個set <Key>:
訊息。
注意 此步驟中描述的機制比前一步驟的效率低得多,因為它可能涉及重複建立新的集合物件而不是修改現有的集合物件。 因此,在設計自己的符合鍵值編碼的物件時,通常應該避免使用它。
3.如果找不到可變集訊息和訪問器,並且接收者的accessInstanceVariablesDirectly
類方法返回YES
,則按順序搜尋名稱如_ <key>
或<key>
的例項變數。 如果找到這樣的例項變數,則返回的代理物件將它接收的任何NSMutableOrderedSet
訊息轉發給例項變數的值,該值通常是NSMutableOrderedSet
或其子類之一的例項。
4.如果所有其他方法都失敗了,那麼只要收到一個可變的set訊息,返回的代理物件就會向mutableOrderedSetValueForKey:
的原始接收者傳送一個setValue:forUndefinedKey:
訊息。
setValue:forUndefinedKey:
的預設實現引發了一個NSUndefinedKeyException
,但是物件可能會覆蓋此行為。
可變集的搜尋方式
mutableSetValueForKey:
的預設實現,給定一個key
引數作為輸入,使用以下過程為接收訪問者呼叫的物件內的一個名為key
的陣列屬性返回一個可變代理集:
1.搜尋方法名稱為add<Key>Object:
和 remove <Key> Object
的方法:(分別對應於NSMutableSet
原始方法addObject:
和removeObject:
)以及add<Key>:
和remove<Key>:
(對應於NSMutableSet
方法unionSet:
和minusSet:
)。如果找到至少一個新增方法和至少一個刪除方法,則返回一個NSMutableSet代理物件,該代理物件傳送add <Key> Object:
,remove <Key> Object:
,add <Key>:
的某種組合, 和remove <Key>:
對於它收到的每個NSMutableSet
訊息的mutableSetValueForKey:
的原始接收者的訊息。
代理物件還使用名稱為“cross:”或“set:”的方法來提高效能(如果可用的話)。
2.如果mutableSetValueForKey:
呼叫的接收者是託管物件,則搜尋模式不會像非託管物件那樣繼續。 有關更多資訊,請參閱“Core Data Programming Guide
”中的託管物件訪問器方法。
3.如果找不到可變集合方法,並且物件不是託管物件,則搜尋名為set <Key>:
的訪問器方法。 如果找到這樣的方法,則返回的代理物件將set <Key>:
訊息傳送給它接收的每個NSMutableSet訊息的mutableSetValueForKey:
的原始接收者。
注意 此步驟中描述的機制的效率遠低於第一步的機制,因為它可能涉及重複建立新的集合物件而不是修改現有的集合物件。 因此,在設計自己的符合鍵值編碼的物件時,通常應該避免使用它。
4.如果找不到可變的set方法和accessor方法,並且accessInstanceVariablesDirectly
類方法返回YES
,則按照順序搜尋名為_ <key>
或<key>
的例項變數。 如果找到這樣的例項變數,則代理物件將它接收的每個NSMutableSet
訊息轉發給例項變數的值,該值通常是NSMutableSet
的例項或其子類之一。
5.如果所有其他方法都失敗了,返回的代理物件通過向mutableSetValueForKey:'的原始接收者傳送
setValue:forUndefinedKey:訊息來響應它收到的任何
NSMutableSet`訊息。
由於筆者水平有限,文中如果有錯誤的地方,或者有更好的方法,還望大神指出。 附上本文的所有 demo 下載連結,【GitHub】。 如果你看完後覺得對你有所幫助,還望在 GitHub 上點個 star。贈人玫瑰,手有餘香。