一. KVC
KVC也就是key-value-coding,即键值编码,最常见的两种用法就是:
1). 对私有变量进行赋值,同样的也可以通过它进行取值
- 对某一个属性进行赋值,可以不用加下划线,它的查找规则应该是:先查找和直接写入的字符串相同的成员变量,如果找不到就找以下划线开头的成员变量;
[p setValue:@170 forKey:@"height"];
[p valueForKey:@"height"];
- forKeyPath是包含了 forKey这个方法的功能的,甚至 forKeyPath方法还有它自己的高级的功能。所以我们在使用kvc的时候,最好用 forKeyPath这个方法。
[p setValue:@200 forKey:@"dog.weight"]; // 报错
[p setValue:@200 forKeyPath:@"dog.weight"]; // 会先去找有没有dog这个key,然后去找dog有没有weight这个属性
2). 字典转模型
简单使用:
obj.name=dic[@"name"];
obj.sex=dic[@"sex"];
obj.age=dic[@"age"];
将以上代码替换为一行代码
[obj setValuesForKeysWithDictionary:dic];
- 字典转模型的时候,字典中的某一个key一定要在模型中有对应的属性,否则会导致程序崩溃;
解决方式:实现一个方法setValue:forUndefinedKey: 这个方法能过滤掉不存在的键值。建议都加上此方法,避免服务器修改了接口后,App因没法及时更新导致程序崩溃
// 在model的h文件中添加:
-(void)setValue:(id)value forUndefinedKey:(NSString *)key;
// 在m文件中实现:
// 并不需要在方法中写任何内容
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
}
- 如果model里面的有不存在于dic中的元素会怎样?
答案是没有问题,对应的属性值是空的 - 如果dic中的key与model中的变量名字不同,应该怎么赋值?
答案也是从setValue:forUndefinedKey方法入手, 完善model中的setValue:forUndefinedKey方法
-(void)setValue:(id)value forUndefinedKey:(NSString *)key{
if([key isEqualToString:@"username"])
{
self.name=value;
}
}
- 如果一个模型中包含了另外的模型对象,是不能直接转化成功的;
二. KVO
KVO,即key-value-observing,利用一个key来找到某个属性并监听其值得改变。其实这也是一种典型的观察者模式。
简单的说,kvo的用法非常简单。
- 添加观察者
- 在观察者中实现监听方法,observeValueForKeyPath: ofObject: change: context:(通过查阅文档可以知道,绝大多数对象都有这个方法,因为这个方法属于NSObject)
- 移除观察者
KVO的底层实现
当一个类的属性被观察的时候,系统会通过runtime动态的创建一个该类的派生类,并且会在这个类中重写基类被观察的属性的setter方法,而且系统将这个类的isa指针指向了派生类,从而实现了给监听的属性赋值时调用的是派生类的setter方法。重写的setter方法会在调用原setter方法前后,通知观察对象值得改变。
1. 如何手动触发KVO?
答: 被监听的属性的值被修改时,就会自动触发KVO。如果想要手动触发KVO,则需要我们自己调用willChangeValueForKey和didChangeValueForKey方法即可在不改变属性值的情况下手动触发KVO,并且这两个方法缺一不可。
2. 直接修改成员变量会触发KVO吗?
答:不会触发
3. 通过KVC修改属性会触发KVO么?
答:会触发
参考: