1.暴力而强大的KVC
访问属性
NSObject遵循了NSKeyValueCoding协议,凡是继承自NSObject的类都是可以使用KVC机制的,并且NSObject已经提供了使用KVC的一些基本方法,如:
- (nullable id)valueForKeyPath:(NSString*)keyPath;
- (void)setValue:(nullable id)value forKeyPath:(NSString*)keyPath;
- (nullable id)valueForUndefinedKey:(NSString*)key;
- (void)setValue:(nullable id)value forUndefinedKey:(NSString*)key;
- (void)setNilValueForKey:(NSString*)key;
- (NSDictionary *)dictionaryWithValuesForKeys:(NSArray *)keys;
- (void)setValuesForKeysWithDictionary:(NSDictionary *)keyedValues;
1、使用KVC间接修改对象属性时,系统会自动判断对象属性的类型,并完成转换。
2、无论是否提供getter/setter方法,无论可见性是怎样,是否有readonly修饰,KVC可以访问成员变量,或者修改成员变量,这使得kvc在某些情况下有非常大的用处。
键值编码
在key字符串中,可以使用 '点符号 '来连接路径,见下面的代码示例
[itemSetValue:@"test" forKeyPath:@"myClass.name"];
此外,还可以应用一些字符做简单运算。@+sum,min,max,avg,count,见下面的代码示例
//属性相加
NSString*sum=[person valueForKeyPath:@"rePerson.@sum.age"];
//数量
NSString*count=[person valueForKeyPath:@"rePerson.@count.age"];
//最大值
NSString*max=[person valueForKeyPath:@"rePerson.@max.age"];
//最小值
NSString*min=[person valueForKeyPath:@"rePerson.@min.age"];
//平均值
NSString*avg=[person valueForKeyPath:@"rePerson.@avg.age"];
OC中和Swift中的区别
1.在OC中,想要对一个属性赋值,必须自己输入属性对应的字符串
[person setValue:@18 forKey:@"age"]
注意,age在定义时定义为int类型,属于基本数据类型,但是在KVC中会将age包装成NSNumber或者NSValue等类型进行操作。
在swift中,进一步的优化是不用再自己输入这个不一定正确的字符串了,我们可以使用#keyPath来输入key,这样编译器会对key进行判断
self.setValue(18, forKeyPath: #keyPath(Person.age))
2.swift中由于引入了可选类型,如果把基本类型定义为可选类型,此时使用KVC会导致无法识别的键值错误,因为KVC是从OC的一种机制,而OC中基本数据类型不存在值缺省,所以无法处理可选的基本数据类型
var name:String?
var phone:Int? =0
self.setValuesForKeys(dic) // 这样写会导致undefinedKey异常
解决方案:
方案一:如果一定要使用KVC,基本数据类型不要定义为可选类型,并且要对基本数据类型进行初始化
var name:String?
var phone:Int = 0
super.init() // 注意使用KVC之前必须点用父类的初始化方法,确保属性完成初始化,否则会报错
self.setValuesForKeys(dic)
方案二:如果基本数据类型必须定义为可选的,则不要使用KVC
name = dic["name"] as! String?
phone = dic["phone"] as! Int?
网友评论