KVC、KVO概述
- KVC(NSKeyValueCoding) "键-值 编码"是一种间接访问对象的属性的机制,在Object2.0之后系统提供了(.)语法来访问属性,在此之前我们需要用KVC来访问。
- KVO(NSKeyValueObserving) "键-值 监听"定义了这样一种机制,当对象属性值发生变化的时候我们能收到一个通知。
注:NSObject类为所有对象提供了一个自动观测能力的NSKeyValueObserving协议。你可以根据具体需求来打开这个监听机制。KVO是根据KVC来实现的。
KVC、KVO的作用
- KVC是一种间接访问对象属性的机制。
获取属性值时可以通过valueForKey:的方法,设置属性值用setValue: forKey:。与此同时KVC还对未定义的属性值定义了valueForUnderfineKey:,在这里我们需要注意的是KVC中的value都必须是对象。我们可以通过KVC给在m文件中声明的属性进行操作,前提是,我们必须知道这个属性的属性名。 - KVO是基于KVC来实现的。
系统已经为我们提供了相关的方法,我们只需要注册这个监听,就能很好的监听属性的值发生改变。 - 注册:下面的方法中,keyPath就是要观察的属性值,options提供的是一个枚举值,就是当键值变化是你可以选择不同的方式,context方便传输你需要的数据。
-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:
(NSKeyValueObservingOptions)options context:(void *)context
- 实现监听方法:其中change里储存了一些数据的变化,比如变化前的数据,变化后的数据。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:
(NSDictionary<NSString *,id> *)change context:(void *)context
KVC键-值 编码
KVC的实现机制
KVC会顺序使用如下技术
- 检查是否存在getter方法-<Key>或者setter方法-set<Key>的方法。
- 如果没有上述方法,则检查是否存在名字为—_<Key>、<Key>的实例变量。
- 如果仍未找到,则调用valueForUnderfineKey和setValue:forUnderfineKey:方法。这些方法的默认实现都是抛出异常,我们可以根据需要重写他们。
示例代码
//使用KVC进行属性的间接访问
Person *aperson = [[Person alloc]init];
[aperson setValue:@"Duck" forKey:@"name"];//等效于aperson.name = @"Duck";
[aperson setValue:@"male" forKey:@"gender"];//等效于aperson.sex = @"male";
Student *astudent = [[Student alloc]init];
[aperson setValue:astudent forKey:@"student"];//通过键值的方式为student属性赋值
[aperson setValue:@"Leo" forKeyPath:@"student.name"];//键路径:通过这个方法可以对属性的属性进行操作。
setValuesForKeysWithDictionary:<#(nonnull NSDictionary<NSString *,id> *)#>
使用这个方法可以将字典里的键值快速的赋值给属性,但是一定要保证属性的名字和字典的键是一致的。如果字典的键多余属性那么就需要我们在这个属性的类中实现下面的一个方法。
-(void)setValue:(id)value forUndefinedKey:(NSString *)key
KVO键-值 监听者
KVO key - value - observer 观察者观察的是属性是否执行了set方法或者是属性是否使用了KVC赋值,只要有赋值的动作,都会执行KVO的回调方法。如果赋值没有通过set方法或者例如(_name = @"新值",就不会出发KVO回调方法,一般KVO崩溃的原因有两种,第一个原因,被观察的对象是一个局部变量,它已经被销毁掉了。第二个原因,观察者被释放掉了,但是没有移除监听。3,注册的监听没有移除掉,又重新注册了监听)。
首先我们需要注册一个观察者,示例代码如下
[self.view addObserver:self forKeyPath:@"backgroundColor" options:
NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
options几个枚举选项的意思
NSKeyValueObservingOptionOld 把更改之前的值提供给处理方法
NSKeyValueObservingOptionNew 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
- observer:观察者(观察对象属性的变化)
- KeyPath:被观察属性的名称
- options:观察属性的新值旧值等一些的配置
- context:可以为KVO的回调方法传值。
KVO的回调方法
当同时监听多个属性的时候,我们需要判断
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
if ([keyPath isEqualToString:@"backgroundColor"]) {//view的背景颜色发生了变化
id oldColour = [change objectForKey:NSKeyValueChangeOldKey];
id newcolour = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"%@,old==%@",NSKeyValueChangeOldKey,oldColour);
NSLog(@"%@,new==%@",NSKeyValueChangeNewKey,newcolour);
}
if ([keyPath isEqualToString:@"name"]) {
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"%@",oldValue);
NSLog(@"%@",newValue);
}
}
- keyPath:属性名称
- object:被观察的对象
- change:变化前后的值都存储在字典中
- context:注册观察者的时候context传过来的值
移除监听的方法
一定要在我们不需要监听的时候,移除监听,不然可能会造成程序崩溃。
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:
(nullable void *)context NS_AVAILABLE(10_7, 5_0);
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
至此有关于KVC和KVO的相关知识解释完成,还有其他不足之处,欢迎提出意见。