KVC探究

438 阅读3分钟

前言

KVC(Key-value coding)键值编码,即iOS的开发中,可以允许开发者通过Key名直接访问对象的属性,或者给对象的属性赋值,而不需要调用明确的存取方法

属性、成员变量与实例变量

属性

用@property修饰的字段,其会自动生成set和get方法外加_key成员变量,即SetKey、key方法,而分类category则不会生成对应的set和get方法,如下所示

@property (nonamotic, copy) NSString *name;

成员变量、实例变量

由属性自动生成,或者写在{}里面直接创建的参数都是成员变量,实例变量也属于成员变量

实例变量的特征:在此类创建的对象不属于基本类型(int、long、float等),需要从其他类获取(例如:UIButton)

@interface Student : NSObject
{
	int _age;
	NSString *_name;
    UIButton *_go; //成员变量、实例变量
}
@end

操作方法

设置值

以LSStudent为例,其有几个类型的属性(或者成员变量)

NSString *name;	//NSString
int age;	//int类型
bool sex;	//BOOL
CGPoint location; //结构体
NSArray *list; //列表
LSStudent *next;  //下一个学生

那么KVC平时常用的赋值则有以下操作,主要使用setValue:forKey和setValue:valueForKeyPath,分别设置键值和子属性键值

//设置name
[student setValue:@"哆啦A梦" forKey:@"name"]; 

//设置age,可以将字符串的数组和NSNumber类型的数值对象转化为int等数值类型
//对数值类型的设置为nil会崩溃
[student setValue:@"18" forKey:@"age"]; 
[student setValue:@YES forKey:@"sex"]; 

//保存结构体为NSValue类型
CGPoint location = {10,20}
NSValue *locationValue = [NSValue valueWithBytes:&location objCType:@encode(CGPoint)]; 
//设置location
[student setValue:locationValue forKey:@"location"];

//给一个对象的子属性赋值
[student setValue:@"我是下一个学生的名字" valueForKeyPath:@"next.name"];

通过集合设置对象与上面稍微不一样,使用到了 setValuesForKeysWithDictionary,可以将对应字典的keyValue赋值到对应的属性上去

NSDictionary *valueDic = @{@"name":@"Cooci",
                 @"age":@20,
                 @"sex":@1};
[student setValuesForKeysWithDictionary:valueDic]; //这样就可以给student赋值了

获取值

属性赋值已经有了解了,获取主要使用valueForKey、valueForKeyPath、dictionaryWithValuesForKeys,分别获取当前键值的value和子属性value,以及对象属性形成的字典

//根据key或者keyPath分别获取属性内容或者子属性内容
NSString *name = [student valueForKey:@"name"];
NSString *nextName = [student valueForKeyPath:@"next.name"];

//根据集合或者属性的值的集合
NSDictionary *valueDic = [student dictionaryWithValuesForKeys:@[@"name", @"age", @"sex"]];

验证键值是否存在

验证属性是否存在validateValue:forKey:error

NSError *error; //异常对象,保存异常信息
[student validateValue:&name forKey:@"names" error:&error]; //error可以传nil

常用的就这些了,其他的就不多介绍了

KVC赋值和取值过程

根据官方文档,KVC赋值和取值经过了如下

赋值

setValueForKey、valueForKeyPath等都经历了如下赋值过程

1、先按顺序查找set[Key]->_set[Key]方法执行

2、如果前面的没找到,那么再判断accessInstanceVariablesDirectly是不是返回YES,默认为YES,此时就按照顺序查找_[key]->_is[Key]->[key]->is[Key]成员变量进行赋值,否则进入下一步

3、accessInstanceVariablesDirectly为NO或者成员变量没有,那么就抛出setValue:forUndefinedKey:的异常

获取值

valueForKey、valueForKeyPath等窦经理了如下获取过程

1、先按顺序查找get[Key] -> [key] -> is[Key] -> _[Key]执行

2、如果属性是NSArray类型,并且对数组属性执行的是objectAtIndex方法,那么就就找objectInAtIndex:方法

3、如果前面的没找到,那么再判断accessInstanceVariablesDirectly是不是返回YES,默认YES,此时按照顺序_[key]->_is[Key]->[key]->is[Key]成员变量进行赋值

4、accessInstanceVariablesDirectly为NO或者成员变量没有,则抛出valueForUndefinedKey:.错误

注意:上面的赋值和获取值的异常方法可以重写,以提醒开发者

总结

使用KVC的时候,可以通过setValueForKey、valueForKey等直接设置和访问属性或者成员变量

当使用KVC的时候需要注意,键值不存在的时候设置值或者获取值,会抛出异常

成员变量或者取名的时候,注意不要使用_、is、get等开区分,这样在特殊情况下,会出现不必要的错误