前言
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等开区分,这样在特殊情况下,会出现不必要的错误