KVC定义
KVC(Key-value coding)键值编码。通过<Key>来直接访问对象的属性,或者为属性赋值,而不是通过明确的set/get方法,这样就可以再运行时动态的访问和修改对象的属性,而不是在编译时确定,它是iOS开发的黑魔法之一,它是很多黑魔法的基础。
注:KVC与点语法有什么区别?
在实现了set\get方法的类中,两者没有太大差异。但是在没有实现set\get方法的类中,点语法无法使用,这时KVC的优势就体现出来了。
KVC的使用
KVC的定义都是对NSObject的扩展来实现的,所以对于所有继承NSObject的类都能使用KVC。
常用的API
//通过key取值
- (nullable id)valueForKey:(NSString *)key;
//通过key设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
//通过keyPath取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
//通过keyPath设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
//验证属性值是否满足条件
- (BOOL)validateValue:(inout id _Nullable * _Nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError;
//取值时如果key不存在,则会调用这个方法,抛出异常
- (nullable id)valueForUndefinedKey:(NSString *)key;
//设值时如果key不存在,则会调用这个方法,抛出异常
- (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key;
//如果设值时,该属性值不支持nil,则会调用这个方法
- (void)setNilValueForKey:(NSString *)key;
setValue:forKey流程图
setValue_forKey流程图概述如下:
- 优先查找set<key>:方法,如果找到执行方法,如果没有找到,再查找_set<key>,如果找到执行方法,如果没有找到,执行下一步
- 检查accessInstanceVariablesDirectly的返回值,如果返回NO,则执行setValue:forUndefinedKey:抛出异常,如果返回YES,默认返回YES,执行下一步
- 按照以下顺序,依次查找成员变量:_<key>、_is<key>、<key>、is<key>,找到则赋值,如果任未找到则调用setValue:forUndefinedKey:然后抛出异常
valueForKey:流程图
valueForKey流程图流程图概述如下:
- 首先按get<key>、<key>、is<key>的顺序查找getter方法,找到直接调用,没有找到执行下一步
- 查找countOf<Key>,objectIn<Key>AtIndex或<Key>AtIndexes方法,如果countOf<Key>和另外两个方法中的一个被找到,那么就会返回一个NSArray集合,否则执行下一步
- 查找countOf<Key>,enumeratorOf<Key>,memberOf<Key>方法,如果三个方法都找到,那么就返回一个NSSet集合
- 检查accessInstanceVariablesDirectly的返回值,如果返回NO,则执行valueforUndefinedKey:抛出异常,如果返回YES,默认返回YES,执行下一步
- 按照以下顺序,依次查找成员变量:_<key>、_is<key>、<key>、is<key>,找到则取值,如果任未找到则调用valueforUndefinedKey:然后抛出异常
KVC处理异常
nil异常
在设值时,给值类型传了nil,则会调用setNilValueForKey:,默认抛出异常,
重写该方法则不抛出异常
undefinedKey异常
在设值时对不存在的key进行了操作,会报错setValue: forUndefinedKey:,重写该方法避免崩溃
KVC使用场景
- 动态地存取值
- 访问和修改私有变量、修改控件的内部属性
[self.textField setValue:[UIColor orangeColor] forKeyPath:@"_placeholderLabel.textColor"];
- model和字典之间的转换
- (void)kvc_dict {
//modal->dict
LPersona *per = [LPersona new];
[per setValue:@10 forKey:@"age"];
[per setValue:@170 forKey:@"height"];
[per setValue:@70 forKey:@"weight"];
[per setValue:@"M" forKey:@"hex"];
NSArray *arr = @[@"age", @"height", @"weight", @"hex"];
NSDictionary *dict = [per dictionaryWithValuesForKeys:arr];
NSLog(@"modal->dict:%@",dict);
//dict->moal
LPersona *per2 = [LPersona new];
NSDictionary *tempDic = @{@"age":@17, @"height":@175, @"weight":@75, @"hex":@"W"};
[per2 setValuesForKeysWithDictionary:tempDic];
NSLog(@"age:%@, height:%@, weight:%@, hex:%@",[per2 valueForKey:@"age"],[per2 valueForKey:@"height"],[per2 valueForKey:@"weight"],[per2 valueForKey:@"hex"]);
}
- 操作集合
- (void)kvc_group {
LPersona *p1 = [LPersona new];
[p1 setValue:@10 forKey:@"age"];
[p1 setValue:@"M" forKey:@"hex"];
LPersona *p2 = [LPersona new];
[p2 setValue:@20 forKey:@"age"];
[p2 setValue:@"W" forKey:@"hex"];
LPersona *p3 = [LPersona new];
[p3 setValue:@30 forKey:@"age"];
[p3 setValue:@"M" forKey:@"hex"];
LPersona *p4 = [LPersona new];
[p4 setValue:@40 forKey:@"age"];
[p4 setValue:@"W" forKey:@"hex"];
LPersona *p5 = [LPersona new];
[p5 setValue:@10 forKey:@"age"];
[p5 setValue:@"M" forKey:@"hex"];
//简单集合运算
NSArray *arr = @[p1,p3,p2,p5,p4];
NSNumber *sum = [arr valueForKeyPath:@"@sum.age"];
NSLog(@"sum:%@",sum);
NSNumber *avg = [arr valueForKeyPath:@"@avg.age"];
NSLog(@"avg:%@",avg);
NSNumber *count = [arr valueForKeyPath:@"@count.age"];
NSLog(@"count:%@",count);
NSNumber *min = [arr valueForKeyPath:@"@min.age"];
NSLog(@"min:%@",min);
NSNumber *max = [arr valueForKeyPath:@"@max.age"];
NSLog(@"max:%@",max);
//去重
NSArray *distinct = [arr valueForKeyPath:@"@distinctUnionOfObjects.age"];
NSLog(@"distinctUnionOfObjects-----------");
for (NSNumber *age in distinct) {
NSLog(@"%f", age.floatValue);
}
//全集
NSArray *arrUnion = [arr valueForKeyPath:@"@unionOfObjects.age"];
NSLog(@"unionOfObjects-----------");
for (NSNumber *age in arrUnion) {
NSLog(@"%f", age.floatValue);
}
}
打印结果:
2019-11-19 11:05:29.556863+0800 KVC探究一[2925:7723768] sum:110
2019-11-19 11:05:29.557050+0800 KVC探究一[2925:7723768] avg:22
2019-11-19 11:05:29.557138+0800 KVC探究一[2925:7723768] count:5
2019-11-19 11:05:29.557219+0800 KVC探究一[2925:7723768] min:10
2019-11-19 11:05:29.557292+0800 KVC探究一[2925:7723768] max:40
2019-11-19 11:05:29.557715+0800 KVC探究一[2925:7723768] distinctUnionOfObjects-----------
2019-11-19 11:05:29.557903+0800 KVC探究一[2925:7723768] 10.000000
2019-11-19 11:05:29.557957+0800 KVC探究一[2925:7723768] 20.000000
2019-11-19 11:05:29.558009+0800 KVC探究一[2925:7723768] 30.000000
2019-11-19 11:05:29.558126+0800 KVC探究一[2925:7723768] 40.000000
2019-11-19 11:05:29.558337+0800 KVC探究一[2925:7723768] unionOfObjects-----------
2019-11-19 11:05:29.558518+0800 KVC探究一[2925:7723768] 10.000000
2019-11-19 11:05:29.559370+0800 KVC探究一[2925:7723768] 30.000000
2019-11-19 11:05:29.559471+0800 KVC探究一[2925:7723768] 20.000000
2019-11-19 11:05:29.559601+0800 KVC探究一[2925:7723768] 10.000000
2019-11-19 11:05:29.559654+0800 KVC探究一[2925:7723768] 40.000000
- KVO
强大的KVO,竟然是基于KVC的
生活如此美好,今天就点到为止。。。
网友评论