[譯]2.4-Key-Value Coding Programming Guide 官方文件第二部分第4節

taoZen發表於2018-11-18

Key-Value Coding Programming Guide 官方文件第二部分第4節 2018.9.20 第一次修正

iOS-KVC官方文件第二部分第4節

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不區分這些。 因此,當keyBOOL時,不應將字串值(例如@“true”或@“YES”)傳遞給setValue:forKey:。 KVC將嘗試呼叫charValue(因為BOOL本身就是一個char),但是NSString沒有實現這個方法,這會導致執行時錯誤。 相反,當keyBOOL時,只傳遞一個NSNumber物件,如@(1)@(YES),作為setValue:forKey: 的值引數。 此限制不適用於iOS,其中BOOL的型別定義為本機布林型別bool,KVC呼叫boolValue,它適用於NSNumber物件或格式正確的NSString物件。

包裝和解包結構體

Table 5-2 下面列出了可以包裝成NSPointNSRangeNSRectNSSize的常用結構體的轉化方法和取值方法

Table 5-2 包裝成NSValue的常用結構型別

Data type Creation method Accessor method
NSPoint valueWithPoint: pointValue
NSRange valueWithRange: rangeValue
NSRect valueWithRect: (macOS only). rectValue
NSSize valueWithSize: sizeValue

不僅NSPointNSRangeNSRectNSSize的可以自動包裝和解包。 結構體型別(即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。贈人玫瑰,手有餘香。

相關文章