成員變量雾棺、實例變量、屬性
- 成員變量:不會自動生成get衬浑、set方法捌浩,成員變量不能用點語法調(diào)用,因為沒有set和get方法工秩,只能使用->調(diào)用尸饺。
- 屬性:屬性會自動生成set和get方法,可以使用.語法
- 實例變量:是一種特殊的成員變量助币,通過class 聲明的成員變量
kvc基礎(chǔ)使用
@interface QHPerson : NSObject
@property (nonatomic,strong)NSString *name;
@property (nonatomic,strong)QHSon *son;
@end
@interface QHSon : NSObject
@property (nonatomic,strong)NSString *nickName;
@end
QHPerson *p = [QHPerson new];
[p setValue:@"qinhan" forKey:@"name"];
NSString *name = [p valueForKey:@"name"];
QHSon *son = [QHSon new];
[p setValue:son forKeyPath:@"son"];
[p setValue:@"sonName" forKeyPath:@"son.nickName"];
NSString *sonName = [p valueForKeyPath:@"son.nickName"];
如果是要多級訪問或讀取
- (nullable id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
kvc賦值過程
我們先來看一下官網(wǎng)的描述
1.先查找
set<Key>
,_set<Key>
兩個方法浪听,如果這兩個方法都沒有實現(xiàn),執(zhí)行步驟22.查找
accessInstanceVariablesDirectly
眉菱,默認(rèn)為YES迹栓,如果為NO,并且1中的方法也沒實現(xiàn)俭缓,則會閃退克伊。3.如果accessInstanceVariablesDirectly為YES.則會按照
_<Key>
,_is<Key>
,<key>
,<isKey>
的順序給成員變量賦值,如果這4個變量名都沒找到华坦,則走4的流程4.如果上面的變量都沒有愿吹,則會走
setValue:forUndefinedKey:
,如果這個方法也沒有實現(xiàn)惜姐,則會出現(xiàn)異常閃退犁跪。我們可以通過這個方法來實現(xiàn)最后的異常處理,防止閃退
kvc取值過程
kvc文檔
相比于賦值,取值過程流程相對更加復(fù)雜一點
1.先按照get<Key>
,<key>
, is<Key>
, or _<key>
的順序取值
2.如果第一步的方法都沒有找到耘拇,則會按照countOf<Key>
撵颊,objectIn<Key>AtIndex
,objectIn<Key>AtIndex
惫叛,<key> AtIndexes
去找
- 如果找到了其中一個,則會創(chuàng)建一個響應(yīng)所有
NSArray
方法的集合代理對象逞刷,并返回該對象嘉涌。如果沒有則會執(zhí)行下一步
-這些方法通過對應(yīng)的.count
、array[index]
夸浅、objectsAtIndexes
仑最,objectAtIndex
訪問到,前提是必須要實現(xiàn)對應(yīng)的方法帆喇,否則會閃退
3.如果2都沒有實現(xiàn)警医,查找名為countOf<Key>
、enumeratorOf<Key>
和memberOf<Key>
這三個方法(對應(yīng)于NSSet
類定義的原始方法)
4.如果3都沒有找到坯钦,則會調(diào)用accessInstanceVariablesDirectly
预皇,如果為YES
,會按照順序取值婉刀,都沒有就會閃退吟温。如果為NO
,就會跳到6
5.判斷取出的屬性值突颊,如果為是對象就會直接返回鲁豪,如果不是會轉(zhuǎn)成NSNumber
返回
-
valueForUndefinedKey
,如果走到這一步?jīng)]有實現(xiàn)這個方法律秃,則會異常爬橡,所以當(dāng)我們自定義kvc的時候,最好實現(xiàn)這個方法
下面附上nsarray代碼
@interface QHArray ()
@property (nonatomic,readwrite,assign) NSUInteger count;
@end
@implementation QHArray
//-(void)incrementCount{
// NSLog(@"%s",__func__);
// self.count ++;
//}
-(NSUInteger)countOfNumbers{
NSLog(@"%s",__func__);
return self.count;
}
-(id)objectInNumbersAtIndex:(NSUInteger)index{
//當(dāng)key使用numbers時棒动,KVC會找到這兩個方法糙申。
NSLog(@"%s",__func__);
return @(index * 2);
}
- (NSArray *)numbersAtIndexes:(NSIndexSet *)indexes
{
NSLog(@"%s",__func__);
return @[@"1",@"2"];
}
-(NSInteger)getNum{
NSLog(@"%s",__func__);//第一個,自己一個一個注釋試
return 10;
}
-(NSInteger)num{
NSLog(@"%s",__func__);//第二個
return 11;
}
-(NSInteger)isNum{
NSLog(@"%s",__func__);//第三個
return 12;
}
//實現(xiàn)
QHArray *arr = [QHArray new];
NSNumber* num = [arr valueForKey:@"num"];
NSLog(@"%@",num);
id ar = [arr valueForKey:@"numbers"];
NSLog(@"ar:%@",ar);
NSLog(@"0:%@ 1:%@",ar[0],ar[1]);
NSIndexSet *sets = [NSIndexSet indexSetWithIndex:1];
NSLog(@"sets:%@", [ar objectsAtIndexes:sets]);
kvc應(yīng)用場景
1.動態(tài)的賦值和取值
setValue:forKey:
、valueForKey:
還有路由setValue:forKeyPath:
迁客,valueForKeyPath:
2.多值操作(model和字典互轉(zhuǎn))
結(jié)合runtime郭宝,獲取成員變量的值,可以實現(xiàn)model和字典轉(zhuǎn)換
3.用KVC實現(xiàn)高階消息傳遞
//KVC實現(xiàn)高階消息傳遞
- (void)transmitMsg{
NSArray *arrStr = @[@"english", @"franch", @"chinese"];
NSArray *arrCapStr = [arrStr valueForKey:@"capitalizedString"];
for (NSString *str in arrCapStr) {
NSLog(@"%@", str);
}
NSArray *arrCapStrLength = [arrCapStr valueForKeyPath:@"capitalizedString.length"];
for (NSNumber *length in arrCapStrLength) {
NSLog(@"%ld", (long)length.integerValue);
}
}