KVC&KVO

作者: NapoleonY | 来源:发表于2016-07-19 11:29 被阅读340次

KVC(key-value coding)

概要

KVC允许开发者通过名字访问属性,无需调用明确的存取方法,这样开发者就能在运行时确定属性的绑定,而不是在编译时。

  • 访问器或实例变量在程序内书写时只能访问该程序的属性。例如setName:,那么在这个地方就只能访问一个属性。与此相对,由于键可以保存在字符串变量中,因此根据变量值是“name”还是“age”,就可以访问不同的属性。

基本处理

KVC允许开发者通过名字()访问属性
常用的方法:

- (id)valueForKey:(NSString *)key;
- (void)setValue:(id)value forKey:(NSString *)key;

还有一种比较常用但很好用的方法,如下所示

//KVC常用方法的使用示例如下
id aPerson = [aGroup valueForKey:@"leader"];
id name = [aPerson valueForKey:@"name"];
//上面的实例可以简化为下面这行代码
id name = [aGroup valueForKeyPath:@"leader.name"];

keyPath称为键路径,用“.”号连接键。同样有两种方法:

- (id)valueForKeyPath:(NSString *)keyPath;
- (void)setValue:(id)value forKeyPath:(NSString *)keyPath;

备注:keyPath版本方法更灵活,而key版本稍微快一些。如果键是通过参数传给我,通常用vauleForKeyPath:,如果键是硬编码的,那我通常会用valueForKey:

KVO(key-value observing)

概要

KVO某个对象的属性改变时通知其它对象的机制。例如MVC中,model层数据变化便可以通过KVO,告知Controller。Cocoa有若干观察机制,包括委托和NSNotification,但是KVO的开销更小。

注意:只有在使用键值编码准则来访问访问器或实例变量的情况下,才可以监视属性的变化。在方法内直接改变实例变量变量值时,就不能监视了。具体KVC准则有三点:

  1. 随访问器方法而改变
  2. 使用setValue:forKey:和键进行改变。此时可能不经由访问器。
  3. 使用setValue:forKeyPath:和键路径进行改变。此时也可能不经由访问器。

基本处理

假设现在要在viewController观察一个model中name的变化,分为三个步骤,代码如下

  1. 首先注册KVO

     [self addObserver:self //观察者
            forKeyPath:@"model.name" //被观察的属性
               options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld //指定属性变化时发送的通知消息中包含变化内容的字典数据中包含什么样的值
        //NSKeyValueObservingOptionNew提供属性改变后的值
        //NSKeyValueObservingOptionOld提供属性改变前的值
               context:nil];//context见后面KVO与context解释,可以为nil
    
  2. 指定监视的属性被改变时,要实现的方法

    - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context
    

{
//keyPath:被检测属性
//object:keyPath所属对象
//change:显示变化内容的字典数据,可按如下方式获得具体值
//id old = [change objectForKey:NSKeyValueChangeOldKey];
//id new = [change objectForKey:NSKeyValueChangeNewKey];
//context:返回注册观察者时指定的值。
}
```

  1. 要停止已经注册的监视,可使用如下方法

    [self removeObserver:self forKeyPath:@"model.name"];
    

进阶KVO

  • KVO与context
    如果我们观察很多个键的话,在实现一个类的时候,把它自己注册成为观察者的话,一个非常重要的点是要传入这个类唯一的context,推荐把以下代码

     static int const PrivateKVOContext;
    

写在这个类.m文件的顶端,然后我们像这样调用 API 并传入 PrivateKVOContext的指针:

```
[otherObject addObserver:self forKeyPath:@"someKey" options:someOptions context:&PrivateKVOContext];
```

然后我们这样写 -observeValueForKeyPath:...的方法

```
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ 
if (context == &PrivateKVOContext) { 
    // 这里写相关的观察代码 
} else { 
    [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
}

}
```
这将确保我们写的子类都是正确的。如此一来,子类和父类都能安全的观察同样的键值而不会冲突。否则我们将会碰到难以 debug 的奇怪行为。

  • NSKeyValueObservingOptionInitial
    我们需要在一个值改变时更新UI,也需要在第一次运行代码的时候更新UI。我们可以在-addObserver:forKeyPath:...时,在option中增加NSKeyValueObservingOptionInitial来设置这件事,使得KVO在调用-addObserver:forKeyPath:...时也被触发一次。

  • NSKeyValueObservingOptionPrior
    注册KVO时,可以添加NSKeyValueObservingOptionPrior选项,当KVO被触发后,我们会收到两个通知:值改变前和值改变后。变更前的通知将会在 change字典中有不同的键。可以像下面这样区分通知是在变更之前还是之后:

     if ([change[NSKeyValueChangeNotificationIsPriorKey] boolValue]) {
        // 改变之前
     } else { 
       // 改变之后
     }
    

设置属性间的依赖

假如有个Person类,类里有三个属性,fullName、firstName、lastName。按照之前的知识,如果需要观察名字的变化,就要分别添加fullName、firstName、lastName三次观察,非常麻烦。如果能够只观察 fullName,并建立fullNamefirstName、lastName的某种依赖关系,当发生变化时,也受到通知,那该多好啊!
可以参考如下文章:

KVO的权衡

  • KVO的一个不足是不能对属性名进行编译检查。
  • 只有一个回调方法,这意味着开发者经常会在那个地方高出一堆不相关的代码。
  • 当你不是某个路径的观察者而调用removeObserver时会发生崩溃。

KVO&KVC相关问题

  1. 怎样手动触发KVO?
    答案
  2. KVO实现原理
    答案
  3. KVC和KVO的keyPath一定是属性么?
    KVO支持实例变量。
  4. KVC的keyPath中的集合运算符如何使用?
    答案

参考文章:

相关文章

  • KVC&KVO

    一.KVC 1.KVC即Key-value coding Key-value coding is a mechan...

  • KVC&KVO

    基本概念 KVC (Key-value coding) C#中可以通过反射读写一个对象的属性,有时候这种方式特别方...

  • KVC&KVO

    KVC(key-value coding) 概要 KVC允许开发者通过名字访问属性,无需调用明确的存取方法,这样开...

  • KVC&KVO

    KVC(Key Value Coding) 既是指NSKeyValueCoding,提供一种机制来间接访问对象的属...

  • iOS【KVC&KVO】

    kvc 1. KVC 1.1 KVC概念 KVC全称是Key Value Coding,定义在NSKeyValue...

  • KVC&KVO(1)

    键值编码的优点: 基于配置的属性访问。 降低耦合性。 简化代码。使用键值编码更新模型的状态。

  • KVC&KVO面试题

    人生就是一场战斗 KVC(Key-Value Coding)键值编码 1.1如何调用私有变量?如何修改系统的只读属...

  • KVC&KVO的部分应用

    KVCKVC实际上是Key-Value Coding的简称,它是一种可以直接通过字符串的名字(key)来间接访问...

  • 程序员面试闪充 -- KVC&KVO

    一、键值编码KVC kvc&kvo视频讲解 1、介绍由于oc的语言特性,使得开发者根本不必进行任何操作就可以进行属...

  • iOS原理篇(一): KVO实现原理

    KVO实现原理 什么是 KVO KVO 基本使用 KVO 的本质 总结 一 、 什么是KVO KVO(Key-Va...

网友评论

  • tjfeng88:KVC和KVO的keyPath一定是属性么?
    KVC支持实例变量和属性,KVO只支持属性不支持实例变量!

本文标题:KVC&KVO

本文链接:https://www.haomeiwen.com/subject/wdymjttx.html