KVC全稱是Key Value Coding,允許開發(fā)者通過
key直接訪問對象的屬性,對對象的屬性進(jìn)行賦值??梢栽谶\行時動態(tài)的訪問和修改對象的屬性。
- KVC最常用的兩個方法也是最基本的操作方法:
-
setValue: forKey:為指定的屬性設(shè)置值 -
valueForKey:獲取指定屬性的值。
-
KVC的簡單用法
定義一個Person類
#import <Foundation/Foundation.h>
@interface Person : NSObject
@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
@implementation Person
- (void)setName:(NSString *)name {
_name = name;
NSLog(@"setName被調(diào)用");
}
@end
然后通過KVC的方式給Person類的屬性賦值:
Person *person = [[Person alloc] init];
[person setValue:@"張三" forKey:@"name"];
[person setValue:[NSNumber numberWithInt:11] forKey:@"age"];
NSLog(@"person.name=%@",[person valueForKey:@"name"]);
NSLog(@"person.age=%@",[person valueForKey:@"age"]);
控制臺輸出如下:

屏幕快照 2019-01-02 21.28.40.png
可以看到對Person類的屬性賦值成功了。并且
- (void)setName:(NSString *)name方面被調(diào)用了。將代碼修改為下面這樣:
@interface Person : NSObject {
NSString *_name;
NSString *name;
}
//@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
給name賦值:
Person *obj = [[Person alloc] init];
[obj setValue:@"小明" forKey:@"name"];
通過查看obj實例可以看出是_name被賦值了。

屏幕快照 2019-01-02 21.43.54.png
將代碼更改為
@interface Person : NSObject {
NSString *_isName;
NSString *name;
}
//@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
調(diào)用代碼不變,可以看到_isName被賦值了

屏幕快照 2019-01-02 21.45.53.png
將代碼修改為
@interface Person : NSObject {
NSString *isName;
NSString *name;
}
//@property (nonatomic, copy) NSString *name;
@property (nonatomic, assign) int age;
@end
再次運行,結(jié)果為name被賦值。

屏幕快照 2019-01-02 21.49.40.png
setValue: forKey:的底層實現(xiàn)機(jī)制:
[person setValue:@"張三" forKey:@"name"]來舉例說明。
- 先尋找Person類的
setName方法,使用setter方法完成賦值。 - 如果沒有找到setName:方法,KVC機(jī)制會檢查
+ (BOOL)accessInstanceVariablesDirectly方法有沒有返回YES,默認(rèn)該方法會返回YES,如果你重寫了該方法讓其返回NO的話,那么在這一步KVC會執(zhí)行setValue:forUndefinedKey:方法 - 如果Person類中沒有
setName方法,KVC會依次去搜索_name,_isName,name,isName成員變量去進(jìn)行賦值操作。無論這些成員變量在什么地方定義和什么控制符修飾,都會進(jìn)行賦值操作。 - 如果上述三條都沒找到,會調(diào)用
setValue:forUndefinedKey:的方法,拋出異常。
在上面的例子中再增加一條代碼,對Person類中沒有的屬性進(jìn)行賦值。
[person setValue:@"dog" forKey:@"dog"];
運行代碼,看到控制臺報錯

屏幕快照 2017-12-25 下午10.06.47.png
可以看到調(diào)用了
setValue:forUndefinedKey:方法,程序結(jié)束。如果這不是我們想要的結(jié)果,我們可以重寫這個方法。
- (void)setValue:(id)value forUndefinedKey:(NSString *)key{
NSLog(@"你嘗試設(shè)置的key=%@不存在",key);
}
這樣就可以避免程序因異常而結(jié)束。
valueForKey:的底層實現(xiàn)機(jī)制:
[person valueForKey:@"name"]來舉例說明。
- 先尋找Person類的
name方法,使用getter方法完成取值。- KVC機(jī)制會檢查
+ (BOOL)accessInstanceVariablesDirectly方法有沒有返回YES,默認(rèn)該方法會返回YES,如果你重寫了該方法讓其返回NO的話,那么在這一步KVC會執(zhí)行valueForUndefinedKey:方法- 如果Person類中沒有
name方法,KVC會依次去搜索_name,_isName,name,isName成員變量去進(jìn)行取值。無論這些成員變量在什么地方定義和什么控制符修飾,都會進(jìn)行取值。- 如果上述三條都沒找到,會調(diào)用
valueForUndefinedKey:的方法,拋出異常。
在上面的例子中再增加一條代碼,對Person類中沒有的屬性進(jìn)行賦值。
NSLog(@"person.dog=%@",[person valueForKey:@"dog"]);
控制臺打?。?/p>

屏幕快照 2017-12-25 下午10.20.00.png
可以看到調(diào)用了
valueForUndefinedKey:的方法,程序因異常結(jié)束。同樣可以重寫valueForUndefinedKey:來避免程序異常結(jié)束。