Key Value Coding
Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property accssor, 如我们有个property叫做foo, 我们可以foo直接访问它,同样我们也可以用KVC来完成[Object valueForKey:@“foo”], 有同学就会问了, 这样做有什么好处呢?主要的好处就是来减少我们的代码量。

下面我们来看看几个例子,就明白了KVO的用法和好处了,假设这样个类叫做People,
@interface People: NSObject

@property (nonatomic, strong) NSString name;
@property (nonatomic, strong) NSNumber
age;

@end
场景1,apple 官网的一个例子,当我们需要统计很多People的时候,每一行是一个人的实例,并且有2列属性,name, age, 这时候我们可以会这样做,

  • (id)tableView:(NSTableView *)tableview
    objectValueForTableColumn:(id)column row:(NSInteger)row {

    People people = [peoleArray objectAtIndex:row];
    if ([[column identifier] isEqualToString:@"name"]) {
    return [people name];
    }
    if ([[column identifier] isEqualToString:@"age"]) {
    return [people age];
    }
    // And so on.
    }
    同样我们也可以用KVC,帮助我们化简这些if, 因为name, age其实都是property, 我们可以直接通过key来访问,所以整理过后是
    People
    people = [peopleArray objectAtIndex:row];
    return [people valueForKey:[column identifier]];
    场景2,这下我们有了server, server的某个api(listPeople??), 会返回我们json格式一个数组,里面包含这样dict{name:xx, age:xx}这样的数据, 我们希望用这些dict数据构造出我们的people来,通常我们的做法是,为我们People类写一个static factory方法专门用来处理dict来, 把dict里面的数据取出来, 然后创建个空的People对象,然后依次设置property。然而当这样类似People的与server交互的类多了,我们就要为每个类都要加上这样的wrapper, 是否有种简单办法来设置这样的属性,当然就是我们的KVC了。
    -(id) initWithDictionary:(NSMutableDictionary*) jsonObject
    {
    if((self = [super init]))
    {
    [self init];
    [self setValuesForKeysWithDictionary:jsonObject];
    }
    return self;
    }
    setValuesForKeysWithDictionary, 会为我们把和dictionary的key名字相同的class proerty设置上dict中key对应的value, 是不是很方便呀,但是有同学又要问了 如果json里面的某些key就是和object的property名字不一样呢,或者有些server返回的字段是objc保留字如”id”, “description”等, 我们也希望也map dict to object, 这时候我们就需要用上setValue:forUndefinedKey, 因为如果我们不处理这些Undefined Key,还是用setValuesForKeysWithDictionary就会 抛出异常。

  • (void)setValue:(id)value forUndefinedKey:(NSString )key
    {
    if([key isEqualToString:@"nameXXX"])
    self.name = value;
    if([key isEqualToString:@"ageXXX"])
    self.age = value;
    else
    [super setValue:value forKey:key];
    }
    所以只要重载这个方法,就可以处理了那些无法跟property相匹配的key了,默认的实现是抛出一个NSUndefinedKeyException,又有同学发问了如果 这时候server返回的People有了内嵌的json(如Products{product1{count:xx, sumPrice:xx}}, product2{} ….),又该怎么办,能把这个内嵌的json转化成我们的客户端的Product类嘛, 当然可以这时候就需要重载setValue:forKey, 单独处理”Products”这个key, 把它wrapper成我们需要的class
    -(void) setValue:(id)value forKey:(NSString
    )key
    {
    if([key isEqualToString:@"products"])
    {
    for(NSMutableDictionary productDict in value)
    {
    Prodcut
    product = [[Product alloc] initWithDictionary:prodcutDict];
    [self.products addObject:product];
    }
    }
    }
    场景3,我们需要把一个数组里的People的名字的首字母大写,并且把新的名字存入新的数组, 这时候通常做法会是遍历整个数组,然后把每个People的name取出来,调用 capitalizedString 然后把新的String加入新的数组中。 有了KVC就有了新做法:

[array valueForKeyPath:@"name.capitalizedString"]

我们看到valueForKeyPath, 为什么用valueForKeyPath, 不用valueForKey, 因为valueForKeyPath可以传递关系,例如这里是每个People的name property的String的capitalizedString property, 而valueForKey不能传递这样的关系,所以对于dict里面的dict, 我们也只能用valueForKeyPath。这里我们也看到KVC对于array(set), 做了特殊处理,不是简单操作collection上,而是 针对这些collection里面的元素进行操作,同样KVC也提供更多地操作,例如@sum这些针对collection,有兴趣的同学可以去用下。

场景4,当我们执行NSArray *products = [people valueForKey:@“products”],我们希望的是[people products],可是people没有这样的方法, KVC又会为我们带来些什么呢?

首先会去找getProdcuts or products or isProducts, 按照这样的顺序去查找,第一个找到的就返回
然后会去找countOfProducts and either objectInProductsAtIndex: or ProductsAtIndexes, 如果找到,就会去找countOfProducts and enumeratorOfProducts and memberOfProducts 这个2个方法都找到了,KVC才会给我们返回一个代理的NSKeyValueArray,用于我们后续的操作(addProduct之类的)。

如果有个变量叫做 products, isProducts, products or isProducts, KVC会直接就使用这样的变量,如果你觉得直接用这样的变量是破坏了封装, 可以禁止这样的行为发生,重载 +accessInstanceVariablesDirectly,返回NO。

简单来说,valueForKey, 会给我们带来一个代理array, 如果我们实现了某些方法,上诉的这些方法只是针对NSArray, 对于mutable的collection, 我们还需要提供其他 方法的实现才行。

Key Value Observing
Key Value Observing, 顾名思义就是一种observer 模式用于监听property的变化,KVO跟NSNotification有很多相似的地方, 用addObserver:forKeyPath:options:context:去start observer, 用removeObserver:forKeyPath:context去stop observer, 回调就是observeValueForKeyPath:ofObject:change:context:。

  • (void)removeObservation {
    [self.object removeObserver:self
    forKeyPath:self.property];
    }

  • (void)addObservation {
    [self.object addObserver:self forKeyPath:self.property
    options:0
    context:(__bridge void*)self];
    }

  • (void)observeValueForKeyPath:(NSString )keyPath
    ofObject:(id)object
    change:(NSDictionary
    )change
    context:(void *)context {
    if ((__bridge id)context == self) {
    // 只处理跟我们当前class的property更新
    }
    else {
    [super observeValueForKeyPath:keyPath ofObject:object
    change:change context:context];
    }
    }

对于KVO来说,我们要做的只是简单update 我们的property数据,不需要像NSNotificationCenter那样关心是否有人在监听你的请求,如果没有人监听该怎么办, 所有addObserver, removeObserver, callback 都是想要监听的你的property的class做的事情。 曾经做个项目,用NSNotificationCenter post Notification在一个network callback里面,可是这时候因为最早的addObserver的class被释放了, 接着生成的addObserver的class, 就接受到了上一个observer该监听的事件,所以造成了错误,那时候的解决方案是为addObserve key做unique,不会2次addObserver 的key是相同的,但是有了KVO, 我们同样可以用KVO来完成,当addOberver的的object remove的时候,就不会有这样的callback被调用了。

KVO给我们提供了更少的代码,和比NSNotification好处,不需要修改被观察的class, 永远都是观察你的人做事情。 但是KVO也有些毛病, 1. 如果没有observer监听key path, removeObsever:forKeyPath:context: 这个key path, 就会crash, 不像NSNotificationCenter removeObserver。 2. 对代码你很难发现谁监听你的property的改动,查找起来比较麻烦。 3. 对于一个复杂和相关性很高的class,最好还是不要用KVO, 就用delegate 或者 notification的方式比较简洁。

Summary
尽量使用KVC可以大大地减少我们的代码量,当遇到property的时候,可以多想想是否可以KVC来帮助我,是否可以用KVC来重构代码, 当需要加入observer模式时,可以考虑下KVO, 在高性能的observer里面,KVO会给我们很好的帮助。

iOS KVC setValuesForKeysWithDictionary的使用的更多相关文章

  1. iOS KVC详细讲解

    iOS KVC详细讲解 什么是KVC? KVC即NSKeyValueCoding,就是键-值编码的意思.一个非正式的 Protocol,是一种间接访问对象的属性使用字符串来标识属性,而不是通过调用存取 ...

  2. iOS 开发之 KVC - setValuesForKeysWithDictionary 解析

    从字典映射到一个对象,这是KVC中的一个方法所提供的,这个方法就是 setValuesForKeysWithDictionary:,非常好用,不需要你来一一的给对象赋值而直接从字典初始化即可,但用的不 ...

  3. iOS - KVC 键值编码

    1.KVC KVC 是 Key-Value Coding 的简写,是键值编码的意思,属于 runtime 方法.Key Value Coding 是 cocoa 的一个标准组成部分,是间接给对象属性设 ...

  4. [iOS] KVC 和 KVO

    开发iOS经常会看见KVO和KVC这两个概念,特地了解了一下. 我的新博客wossoneri.com link KVC Key Value Coding KVC是一种用间接方式访问类的属性的机制.比如 ...

  5. iOS:KVC和KVO

    来源:  对月流 链接:http://www.jianshu.com/p/f1393d10109d 写在前面: 关于KVC和KVO各种博客多了去了,重新整理下,就当是温习一下吧,也还算是个新手,不对的 ...

  6. iOS KVC(Key-Value Coding)

    常见用法: 获取值 valueForKey: 依据属性名取值 valueForKeyPath: 依据路径取值(如:[person valueForKeyPath:@"car.price&qu ...

  7. 转载 --ios 模型-setValuesForKeysWithDictionary

    应用场景:app请求后端数据,返回的数据是JSON形式,如: { "is_favor" = 0; "is_follow" = 0; "is_prais ...

  8. iOS KVC,KVO

    链接(写得不错,着重kvc):http://www.cocoachina.com/industry/20140224/7866.html 链接:http://www.cnblogs.com/kensh ...

  9. iOS KVC/KVO/KVB

    看了那么多博客.描述那么复杂,其实KVC很简单,没描述的那么复杂,所以写一篇简单的易于理解的博文,切入正文: 1.KVC底层是通过runtime对method和value操作  比如说如下的一行KVC ...

随机推荐

  1. vs2013安装visual assist和viemu之后提示功能等无效解决

    1.vs2013安装了上面两个软件之后会发生va功能无效,经过一番谷歌百度后找到了解决方案 1.打开注册表 2.直接搜索TrackCaretVisibility这个键值,找到后把他的值修改成00 此篇 ...

  2. android-misc-widgets四向(上下左右)抽屉bug修复版--转载

     android-misc-widgets四向(上下左右)抽屉bug修复版 2013-08-04 08:58:13 标签:bug down top panel slidingdrawer 原创作品,允 ...

  3. getByClassName2016/4/21

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  4. hadoop yarn

    简介: 本文介绍了 Hadoop 自 0.23.0 版本后新的 map-reduce 框架(Yarn) 原理,优势,运作机制和配置方法等:着重介绍新的 yarn 框架相对于原框架的差异及改进:并通过 ...

  5. Java的动态加载及其安全性问题

    1.什么是动态加载 Class Loaders是动态加载Java类与Resource的一种机制.它支持Laziness,type-safe linkage,user-defined extensibi ...

  6. Android开机启动Activity或者Service方法(转载)

    这段时间在做Android的基础开发,现在有一需求是开机启动,按照网上某些博文教程做了下,始终不成功,一开机总是提示所启动的应用程序意外终止,于是参考了Android SDK doc,终于解决问题,下 ...

  7. Sphinx配置过程

    http://www.oschina.net/question/84274_11938 http://www.ibm.com/developerworks/library/os-php-sphinxs ...

  8. 创建 AngularJS 自定义过滤器,带自定义参数

    Angularjs过滤器是 angularjs非常棒的特性之一.有朝一日,你可能需要使用自定义过滤器,幸运的是,你找到了这篇博文. 下面显示的是自定义过滤器长什么样子(请注意myfilter): &l ...

  9. angularjs中动态为audio绑定src

    今天在angularjs中用audio的时候碰到的这些问题,查阅http://www.cnblogs.com/rachelanlan/p/3598070.html获得解决,感谢! <div cl ...

  10. Android Studio中有没有类似于Eclipse中的ctrl+2+L的快捷键? \Android Studio快捷键之代码提示

    问:Android Studio中有没有类似于Eclipse中的ctrl+2+L的快捷键? 答:有,as中的快捷键是Ctrl+Alt+V AndroidStudio和Eclipse常用快捷键对比 功能 ...