Key-Value Coding Programming Guide 蘋果文檔
KVC: Key-Value Coding
一、KVC 的簡單使用
1、普通賦值
1.1、setter
-- llvm
MyPerson *person = [[MyPerson alloc] init];
person.name = @"setName";
person.age = 18;
person->myName = @"yName";
NSLog(@"%@ - %d - %@",person.name,person.age,person->myName);
// 輸出:setName - 18 - yName
1.2悄蕾、Key-Value Coding
KVC
[person setValue:@"張三" forKey:@"name"];
2、集合類型
person.array = @[@"1",@"2",@"3"];
// 修改數(shù)組
// person.array[0] = @"100";
// 1: 建一個新的數(shù)組 - KVC 賦值
NSArray *array = [person valueForKey:@"array"];
array = @[@"100",@"2",@"3"];
[person setValue:array forKey:@"array"];
NSLog(@"%@",[person valueForKey:@"array"]);
// 輸出:100 2 3
// 2
NSMutableArray *mArray = [person mutableArrayValueForKey:@"array"];
mArray[0] = @"200";
NSLog(@"%@",[person valueForKey:@"array"]);
// 輸出:200 2 3
3础浮、訪問非對象屬性
以結(jié)構(gòu)體為例:
// 結(jié)構(gòu)體
typedef struct {
float x, y, z;
} ThreeFloats;
ThreeFloats floats = {1.,2.,3.};
NSValue *value = [NSValue valueWithBytes:&floats objCType:@encode(ThreeFloats)];
[person setValue:value forKey:@"threeFloats"];// 設(shè)置
NSValue *value1 = [person valueForKey:@"threeFloats"];// 取值
NSLog(@"%@",value1);
// 輸出:{length = 12, bytes = 0x0000803f0000004000004040}
ThreeFloats th;
[value1 getValue:&th];
NSLog(@"%.2f-%.2f-%.2f",th.x,th.y,th.z);
// 輸出:1.00-2.00-3.00
4帆调、keyPath
MyStudent *student = [MyStudent alloc];
student.subject = @"subStr嗎";
person.student = student;
[person setValue:@"subStr啊" forKeyPath:@"student.subject"];
NSLog(@"%@",[person valueForKeyPath:@"student.subject"]);
// 輸出:subStr啊
5奠骄、數(shù)組Array
的操作
#pragma mark - array 取值
- (void)arrayDemo{
MyStudent *p = [MyStudent new];
p.penArr = [NSMutableArray arrayWithObjects:@"pen0", @"pen1", @"pen2", @"pen3", nil];
NSArray *arr = [p valueForKey:@"penArr"]; // 動態(tài)成員變量
NSLog(@"pens = %@", arr);
/* pens = (
pen0,
pen1,
pen2,
pen3
)*/
//NSLog(@"%@",arr[0]);
NSLog(@"%d",[arr containsObject:@"pen9"]);// 0 false
// 遍歷
NSEnumerator *enumerator = [arr objectEnumerator];
NSString* str = nil;
while (str = [enumerator nextObject]) {
NSLog(@"%@", str);
}
}
6、字典Dictionary
- (void)dictionaryDemo {
// 1:
NSDictionary *dict = @{
@"name":@"李四",
@"nick":@"小四",
@"subject":@"iOS",
@"age":@18,
@"length":@180
};
MyStudent *p = [[MyStudent alloc] init];
// 字典轉(zhuǎn)模型
[p setValuesForKeysWithDictionary:dict];
/**
(lldb) p *$0
(NSDictionary) $1 = {
[0] = {
key = 0x000000010585e3e0 @"age"
value = 0x947567b2920d34b5 (int)18
}
[1] = {
key = 0x000000010585e3a0 @"subject"
value = 0x000000010585e3c0 @"iOS"
}
[2] = {
key = 0x000000010585e360 @"nick"
value = 0x000000010585e380 @"小四"
}
[3] = {
key = 0x000000010585e0c0 @"name"
value = 0x000000010585e340 @"李四"
}
[4] = {
key = 0x000000010585e400 @"length"
value = 0x947567b2920d3ed5 (int)180
}
}
*/
// 2:
// 數(shù)組 轉(zhuǎn) 模型 到 字典
NSArray *array = @[@"name",@"age"];
NSDictionary *dict2 = [p dictionaryWithValuesForKeys:array];
NSLog(@"%@",dict2);
/**
(lldb) p *$2
(NSDictionary) $3 = {
[0] = {
key = 0x000000010585e0c0 @"name"
value = 0x000000010585e340 @"李四"
}
[1] = {
key = 0x000000010585e3e0 @"age"
value = 0x947567b2920d34b5 (int)18
}
}
*/
}
7番刊、KVC 消息傳遞
- (void)arrayMessagePass{
NSArray *array = @[@"hank",@"anmyli",@"kod",@"CC"];
NSArray *lenStr= [array valueForKeyPath:@"length"];
NSLog(@"%@",lenStr);// 消息從 array 傳遞給了 string
// string.length
// (
// 4,
// 6,
// 3,
// 2
// )
NSArray *nStr= [array valueForKeyPath:@"uppercaseString"];// lowercaseString uppercaseString
NSLog(@"%@",nStr);// 字母大寫
// 輸出:
// (
// HANK,
// ANMYLI,
// KOD,
// CC
// )
}
8戚揭、NSSet
8.1)set
的 KVC
- (void)setNesting{
// NSSet *s = [NSSet setWithArray:@[@"1",@"3",@"8",@"4"]];
// NSLog(@"%@",s);//
NSMutableSet *personSet1 = [NSMutableSet set];
for (int i = 0; i < 6; i++) {
MyStudent *person = [MyStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personSet1 addObject:person];
}
NSLog(@"personSet1 = %@", [personSet1 valueForKey:@"length"]);
// 輸出:
// personSet1 = {(
// 175,
// 181,
// 177,
// 179
// )}
NSMutableSet *personSet2 = [NSMutableSet set];
for (int i = 0; i < 6; i++) {
MyPerson *person = [MyPerson new];
NSDictionary* dict = @{
@"name":@"jerry",
@"age":@(18+i),
// @"nick":@"Cat",
// @"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personSet2 addObject:person];
}
NSLog(@"personSet2 = %@", [personSet2 valueForKey:@"age"]);
// 輸出:
// personSet2 = {(
// 21,
// 20,
// 23,
// 19,
// 22,
// 18
// )}
// 嵌套set
NSSet* nestSet = [NSSet setWithObjects:personSet1, personSet2, nil];
// 交集
NSArray* arr1 = [nestSet valueForKeyPath:@"@distinctUnionOfSets.name"];
NSLog(@"arr1 = %@", arr1);
// 輸出:
// arr1 = {(
// Tom,
// jerry
// )}
}
8.2)set
和 array
區(qū)別:
1、代碼調(diào)試
執(zhí)行如下代碼:
NSMutableSet *personSet1 = [NSMutableSet set];
NSMutableArray *personArr1 = [NSMutableArray array];
for (int i = 0; i < 6; i++) {
MyStudent *person = [MyStudent new];
NSDictionary* dict = @{
@"name":@"Tom",
@"age":@(18+i),
@"nick":@"Cat",
@"length":@(175 + 2*arc4random_uniform(6)),
};
[person setValuesForKeysWithDictionary:dict];
[personSet1 addObject:person];
[personArr1 addObject:person];
}
打個斷點在 for 所在行撵枢,調(diào)試信息如下:
(lldb) p malloc_size((__bridge void *)personArr1)
(size_t) $0 = 48
(lldb) p malloc_size((__bridge void *)personSet1)
(size_t) $1 = 32
(lldb)
繼續(xù)執(zhí)行,并調(diào)試:
(lldb) po personArr1
<__NSArrayM 0x600003e33f60>(
<MyStudent: 0x600003e307e0>,
<MyStudent: 0x600003e33f90>,
<MyStudent: 0x600003e33fc0>,
<MyStudent: 0x600003e30750>,
<MyStudent: 0x600003e324f0>,
<MyStudent: 0x600003e308a0>
)
(lldb) po personSet1
{(
<MyStudent: 0x600003e33fc0>,
<MyStudent: 0x600003e33f90>,
<MyStudent: 0x600003e30750>,
<MyStudent: 0x600003e324f0>,
<MyStudent: 0x600003e307e0>,
<MyStudent: 0x600003e308a0>
)}
8.2)官方文檔 OC 下 - Values and Collections
NSSet
- NSSet :
NSArray
:
這里把字典的圖示也放在這里便于比較精居,Dictionary
:
set
和array
主要區(qū)別:
array
有序锄禽,數(shù)據(jù)可重復(fù);
set
無序靴姿,數(shù)據(jù)不重復(fù)沃但。
二、KVC 原理探究 基于蘋果官方文檔
1佛吓、Search Pattern for the Basic Setter
setter
的流程:
- 先找
set<Key>:
or_set<Key>
宵晚; - 若沒找到且
accessInstanceVariablesDirectly
returnsYES
,則繼續(xù)找_<key>
,_is<Key>
,<key>
, oris<Key>
; - 沒找著則: invoke
setValue:forUndefinedKey:
.维雇。默認情況下會引發(fā)一個異常淤刃,但NSObject
的子類可能提供特定于鍵的行為
2、Search Pattern for the Basic Getter
getter
流程:
- 實例中搜索吱型,先找
get<Key>
,<key>
,is<Key>
, or_<key>
逸贾,找到了就調(diào)用去·5·中處理結(jié)果;沒找著則繼續(xù)下一步津滞; - 搜索名稱與模式
countOf<Key>
和objectIn<Key>AtIndex:
(對應(yīng)于NSArray
類定義的基本方法) 以及<key>AtIndexes:
(對應(yīng)于NSArray 方法objectsAtIndexes:
)铝侵;
2.1.、如果找到第1個或至少兩個中的一個触徐,則創(chuàng)建一個集合代理對象咪鲜,該對象響應(yīng)所有NSArray
方法并返回該方法。否則撞鹉,繼續(xù)執(zhí)行步驟3疟丙;
2.2、代理對象隨后將接收到的任何NSArray
消息轉(zhuǎn)換為countOf<Key>
鸟雏、objectIn<Key>AtIndex:
和<Key> AtIndexes:
的一些組合隆敢,這些組合將消息發(fā)送給創(chuàng)建它的符合鍵值編碼的對象。如果原始對象還實現(xiàn)了一個名為get<Key>:range:
的可選方法崔慧,代理對象也會在適當(dāng)?shù)臅r候使用它拂蝎。實際上,代理對象與鍵值編碼兼容的對象一起工作惶室,允許底層屬性像NSArray
一樣工作温自,即使它不是NSArray
玄货。 - 如果沒有找到簡單的訪問方法或數(shù)組訪問方法組,查找下面三個方法悼泌,
countOf<Key>
松捉,enumeratorOf<Key>
,memberOf<Key>:
(對應(yīng)于NSSet
類定義的原語方法)。
3.1馆里、如果這三個方法都找到了隘世,創(chuàng)建一個集合代理對象,它響應(yīng)所有NSSet
方法并返回那個鸠踪。否則丙者,繼續(xù)執(zhí)行步驟4。
3.2营密、這個代理對象隨后將它接收到的任何NSSet
消息轉(zhuǎn)換為countOf<Key>
械媒、enumeratorOf<Key>
和memberOf<Key>:
消息的組合,并發(fā)送給創(chuàng)建它的對象评汰。實際上纷捞,代理對象與遵循鍵值編碼的對象一起工作,允許底層屬性像NSSet
一樣運行被去,即使它不是NSSet
主儡。 - 如果沒有找到簡單的訪問方法或集合訪問方法組,并且如果接收方的類方法
accessinstancevariables
返回YES
惨缆,那么按照順序搜索一個實例變量:_<key>
缀辩,_is< key>
,<key>
踪央,或is< key>
臀玄。如果找到,直接獲取實例變量的值并繼續(xù)執(zhí)行步驟5畅蹂。否則健无,繼續(xù)執(zhí)行步驟6。 - 如果檢索到的屬性值是一個對象指針液斜,只需返回結(jié)果累贤。
如果值是NSNumber支持的標(biāo)量類型,將其存儲在NSNumber實例中并返回少漆。
如果結(jié)果是NSNumber不支持的標(biāo)量類型臼膏,轉(zhuǎn)換為NSValue對象并返回它。 - 如果所有其他方法都失敗示损,則調(diào)用
valueForUndefinedKey:
渗磅。這在默認情況下會引發(fā)一個異常,但是NSObject
的一個子類可能提供特定于鍵的行為。
3始鱼、Getting
/Setting
Attribute Values Using Keys
更多信息在蘋果文檔中比較詳細仔掸,這里不再多做介紹。