Key-Value Coding Programming Guide 官方文件第二部分第4節 2018.9.20 第一次修正
Key-Value Coding Fundamatals--Representing Non-Object Values
表示非物件值
通過NSObject
使用物件和非物件屬性提供的鍵值編碼協議方法的預設實現。 預設實現自動在物件引數或返回值以及非物件屬性之間進行轉換。 這允許即使儲存的屬性是標量或結構體,基於key的getter和setter的命名也保持一致。
注意 因為Swift中的所有屬性都是物件,所以本節僅適用於Objective-C屬性。
當你呼叫協議的其中一個getter時,valueForKey:
,預設實現根據Accessor Search Patterns中描述的規則 確定為指定鍵提供值的特定訪問器方法或例項變數。 如果返回值不是物件,則getter使用此值初始化NSNumber
物件(對於標量)或NSValue
物件(對於結構體)並返回該值。
同樣,預設情況下,像setValue:forKey:
這樣的setter在給定特定鍵的情況下確定屬性的訪問器或例項變數所需的資料型別。 如果資料型別不是物件,則setter首先向傳入值物件傳送適當的<type> Value
訊息以提取基礎資料,並儲存該資料。
注意 當您使用非物件屬性的nil值呼叫其中一個KVC協議
setter
時,setter沒有明顯的一般操作過程。 因此,它向接收setter呼叫的物件傳送setNilValueForKey:
訊息。 此方法的預設實現引發NSInvalidArgumentException
異常,但子類可能會覆蓋此行為,如Handling Non-Object Values中所述,例如設定標記值或提供有意義的預設值。
包裝和解包標量型別
Table 5-1 列出預設KVC實現使用NSNumber
例項包裝的標量型別。 對於每種資料型別,該表顯示用於初始化NSNumber
基礎屬性值以提供getter返回值的建立方法。 然後顯示用於在設定操作期間從setter輸入引數中提取值的訪問器方法。
Table 5-1 標量型別包含在NSNumber
物件中
Data type | Creation method | Accessor method |
---|---|---|
BOOL |
numberWithBool: |
boolValue (in iOS) charValue (in macOS)* |
char |
numberWithChar: |
charValue |
double |
numberWithDouble: |
doubleValue |
float |
numberWithFloat: |
floatValue |
int |
numberWithInt: |
intValue |
long |
numberWithLong: |
longValue |
long long |
numberWithLongLong: |
longLongValue |
short |
numberWithShort: |
shortValue |
unsigned char |
numberWithUnsignedChar: |
unsignedChar |
unsigned int |
numberWithUnsignedInt: |
unsignedInt |
unsigned long |
numberWithUnsignedLong: |
unsignedLong |
unsigned long long |
numberWithUnsignedLongLong: |
unsignedLongLong |
unsigned short |
numberWithUnsignedShort: |
unsignedShort |
注意 *在macOS中,由於歷史原因,BOOL的型別定義為
signed char
,而KVC不區分這些。 因此,當key
為BOOL
時,不應將字串值(例如@“true”或@“YES”)傳遞給setValue:forKey:
。 KVC將嘗試呼叫charValue
(因為BOOL
本身就是一個char
),但是NSString
沒有實現這個方法,這會導致執行時錯誤。 相反,當key
為BOOL
時,只傳遞一個NSNumber
物件,如@(1)
或@(YES)
,作為setValue:forKey:
的值引數。 此限制不適用於iOS,其中BOOL的型別定義為本機布林型別bool,KVC呼叫boolValue,它適用於NSNumber
物件或格式正確的NSString
物件。
包裝和解包結構體
Table 5-2 下面列出了可以包裝成NSPoint
,NSRange
,NSRect
和NSSize
的常用結構體的轉化方法和取值方法
Table 5-2 包裝成NSValue
的常用結構型別
Data type | Creation method | Accessor method |
---|---|---|
NSPoint | valueWithPoint: | pointValue |
NSRange | valueWithRange: | rangeValue |
NSRect | valueWithRect: (macOS only). | rectValue |
NSSize | valueWithSize: | sizeValue |
不僅NSPoint
,NSRange
,NSRect
和NSSize
的可以自動包裝和解包。 結構體型別(即Objective-C型別中字串以{
開頭編碼的型別)也可以包成NSValue物件中。 例如,參考5-1表格中宣告的結構體和類介面。
Listing 5-1 使用自定義結構體的類
typedef struct {
float x, y, z;
} ThreeFloats;
@interface MyClass
@property (nonatomic) ThreeFloats threeFloats;
@end
複製程式碼
使用名為myClass
的類的例項,可以使用KVC獲取threeFloats值
NSValue* result = [myClass valueForKey:@"threeFloats"];
複製程式碼
valueForKey:
的預設實現呼叫threeFloats
的getter方法,然後返回包含在NSValue
物件中的結果。
同樣,您可以使用KVC設定threeFloats
值:
ThreeFloats floats = {1., 2., 3.};
NSValue* value = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
[myClass setValue:value forKey:@"threeFloats"];
複製程式碼
預設實現使用getValue:方法解包值,然後使用setThreeFloats:
生成的結構體進行呼叫。
由於筆者水平有限,文中如果有錯誤的地方,或者有更好的方法,還望大神指出。 附上本文的所有 demo 下載連結,【GitHub】。 如果你看完後覺得對你有所幫助,還望在 GitHub 上點個 star。贈人玫瑰,手有餘香。