赞
踩
KVC
的全称是Key-Value Coding
,翻译成中文叫做键值编码
KVC提供了一种间接访问属性方法或成员变量的机制,允许通过字符串来访问对应的属性方法或成员变量
它是一个非正式的Protocol,提供一种机制来间接访问对象的属性,而不是通过调用Setter、Getter方法访问。KVO
就是基于 KVC
实现的关键技术之一。
通过key
设值/取值
//直接通过Key来取值
- (nullable id)valueForKey:(NSString *)key;
//通过Key来设值
- (void)setValue:(nullable id)value forKey:(NSString *)key;
通过keyPath
(即路由
)设值/取值
//通过KeyPath来取值
- (nullable id)valueForKeyPath:(NSString *)keyPath;
//通过KeyPath来设值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath;
其他方法
//默认返回YES,表示如果没有找到Set<Key>方法的话,会按照_key,_iskey,key,iskey的顺序搜索成员,设置成NO就不这样搜索 + (BOOL)accessInstanceVariablesDirectly; //KVC提供属性值正确性验证的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。 - (BOOL)validateValue:(inout id __nullable * __nonnull)ioValue forKey:(NSString *)inKey error:(out NSError **)outError; //这是集合操作的API,里面还有一系列这样的API,如果属性是一个NSMutableArray,那么可以用这个方法来返回。 - (NSMutableArray *)mutableArrayValueForKey:(NSString *)key; //如果Key不存在,且KVC无法搜索到任何和Key有关的字段或者属性,则会调用这个方法,默认是抛出异常。 - (nullable id)valueForUndefinedKey:(NSString *)key; //和上一个方法一样,但这个方法是设值。 - (void)setValue:(nullable id)value forUndefinedKey:(NSString *)key; //如果你在SetValue方法时面给Value传nil,则会调用这个方法 - (void)setNilValueForKey:(NSString *)key; //输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。 - (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
key
:只能接受当前类所具有的属性,不管是自己的,还是从父类继承过来的
keypath
:除了能接受当前类的属性,还能接受当前类属性的属性,即可以接受关系链,然后进行深层访问
People *t1 = [[People alloc] init];
Address *t2 = [[Address alloc] init];
t1.Ad = t2;
[t1 setValue:@"顶针" forKey:@"name"];
NSLog(@"%@", [t1 valueForKey:@"name"]);
输出:
输出:
同样,也可以通过KVC进行批量操作,使用对象调用setValuesForKeysWithDictionary
:方法时,可以传入一个包好key
、value
的字典进去,KVC
可以将所有数据按照属性名和字典的key进行匹配,并将value
给对象的属性赋值
NSDictionary *dictionarySecond = @{@"name":@"顶针", @"age":@"11", @"sex":@"女"};
People *t3 = [[People alloc] init];
[t3 setValuesForKeysWithDictionary:dictionarySecond];
NSLog(@"name = %@, age = %ld, sex = %@",t3.name, (long)t3.age, t3.sex);
如果model
属性和dic
不匹配,可以重写方法-(void)setValue:(id)value forUndefinedKey:(NSString *)key。
这一点后面会讲到
字典转模型
NSDictionary *dictionary = @{@"name":@"stu1", @"age":@66, @"sex":@"nv"};
StudentModel *model = [[StudentModel alloc] init];
[model setValuesForKeysWithDictionary:dictionary];
NSLog(@"model.name:%@",model.name);
NSLog(@"model.age:%@",model.age);
NSLog(@"model.sex:%@",model.studentSex);
输出:
模型转字典
NSDictionary *tempModelDictionary = [model dictionaryWithValuesForKeys:@[@"name", @"age", @"studentSex"]];
NSLog(@"tempModelDictionary : %@", tempModelDictionary);
输出:
在日常开发中,针对对象属性的赋值,一般有以下两种方式
setter
方法赋值LGPerson *person = [[LGPerson alloc] init];
// 1、一般setter 方法
person.name = @"CJL_哈哈";
// 2、KVC方式
[person setValue:@"CJL_嘻嘻" forKey:@"name"];
下面针对setValue:forKey
进行底层原理探索
在这里,我们通过Key-Value Coding Programming Guide苹果官方文档来研究,针对设值流程,有如下说明
当调用setValue:forKey:
设置属性value
时,其底层的执行流程为
set<Key>:-> _set<Key> -> setIs<Key>
如果有其中任意一个setter
方法,则直接设置属性的value
(主注意:key
是指成员变量名,首字符大小写需要符合KVC
的命名规范)
如果都没有则进入第二步
setter
方法,则查找accessInstanceVariablesDirectly
是否返回YES
如果返回YES
,则查找间接访问的实例变量进行赋值,查找顺序为:_<key> -> _is<Key> -> <key> -> is<Key>
如果找到其中任意一个实例变量,则赋值,如果都没有,则进入【第三步】
setter
方法 或者 实例变量都没有找到,系统会执行该对象的setValue:forUndefinedKey
:方法,默认抛出NSUndefinedKeyException
类型的异常综上所述,KVC
通过 setValue:forKey:
方法设值的流程以设置LGPerson
的对象person
的属性name
为例,如下图所示
当调用valueForKey:
时,其底层的执行流程如下
getKey、key、isKey、_key
的顺序查找方法,找到直接调用取值+ (BOOL)accessInstanceVariablesDirectly
的返回值,若返回NO,则直接抛出NSUnknowKeyExpection
异常;YES
,则按照_key、_isKey、key、isKey
的顺序查找成员变量,找到则取值;valueForUndefinedKey
:抛出NSUnknowKeyExpection
异常;Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。