KVC
KVC概念
KVC全称是Key-Value-Coding,键值编码,可以通过一个key来访问某个属性。
KVC基本API方法
- (nullable id)valueForKey:(NSString *)key; //直接通过Key来取值
- (void)setValue:(nullable id)value forKey:(NSString *)key; //通过Key来设值
- (nullable id)valueForKeyPath:(NSString *)keyPath; //通过KeyPath来取值
- (void)setValue:(nullable id)value forKeyPath:(NSString *)keyPath; //通过KeyPath来设值
在这里要注意的是前两种方法是KVC的设值,后两种方法是KVC的取值。
其他方法
// 默认返回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;
// 使用字典为Model赋值
- (void)setValuesForKeysWithDictionary:(NSDictionary<NSString *, id> *)keyedValues;
// 输入一组key,返回该组key对应的Value,再转成字典返回,用于将Model转到字典。
- (NSDictionary<NSString *, id> *)dictionaryWithValuesForKeys:(NSArray<NSString *> *)keys;
首先我们来看设值
设值
最简单的是用key方法直接设值:
Person* person = [[Person alloc]init];
[person setValue:@namevalue forKey:@"name"];
还可以使用keyPath方法进行多重设值
Person* person = [[Person alloc]init];
[person setValue:@1 forKeyPath:@"dog.age"];
id age = [person valueForKeyPath:@"dog.age"];
NSLog(@"%@", age);
Dog类和Person类是两个继承NSObject的类,先在Person类里面设置Dog类型的属性,在Dog类里设置int类型的age属性,即可完成设值过程。
取值
在取值过程中,优先级是最重要的一点,一定要搞清楚KVC取值的优先级,我们可以先来看下图:
第一优先级
在这个过程中,第一优先级是getter方法,也就是说在取值的时候,先判断有没有getter方法,如果有的话直接取值成功,不需要后面的步骤了。
- (NSString*)name {
return @"666";
}
- (NSString*)getName {
return @"get666";
}
- (NSString*)isName {
return @"is666";
}
我们在Person的m文件中把三个getter方法全写上,此时打印:
Person* person = [[Person alloc]init];
NSString* name = [person valueForKey:@"name"];
NSLog(@"%@", name);
我们发现在所有getter方法里面,优先级最高的是getName方法,然后我们把这个方法注释掉,经过实验得出结论:
在三个getter方法中,优先级排序:
getKey > key > isKey
第二优先级
我们发现上图中在第二优先级前面有一个方法,这个方法是什么呢,我们来看看:
+ (BOOL)accessInstanceVariablesDirectly
这个方法是BOOL类型,用来判断是否需要查找第二优先级,默认情况下为Yes,如果返回值改为No,就跳过查找第二优先级。
此时我们对成员变量通过重写init方法进行赋值:
- (instancetype)init {
if (self = [super init]) {
//成员变量
_name = @"_name";
_isName = @"_isName";
name = @"name";
isName = @"isName";
}
return self;
}
在进行第二级优先级测试的时候,先把第一优先级的方法注释起来,然后运行程序:
同样用刚才相同的方法进行测试,发现第二级方法的优先级:
_key > _iskey > key > iskey
那么如果两种情况都没有呢?
我们将代码都注释掉来试试:
这时候程序编译没问题,运行时就会报经典的Undefine问题了。
KVC问题其实是一个比较抽象的问题,如果文章难以理解的话,这里推荐一个视频博主,关于此节内容讲解十分细致:
KVC视频链接