KVC(键值编码)

动态设置:

setValue:属性值 forKey:属性名(用于简单路径)

setValue:属性值 forKeyPath:属(用于复合路径,例如Person有一个Account类型的属性,那么person.account就是一个复合属性)

动态读取:

valueForKey:属性名

valueForKeyPath:属性名(用于复合路径)

KVO(键值监听)

常规使用

1.注册指定key路径的监听器

- (void)addObserver:(NSObject *)anObserver
forKeyPath:(NSString *)keyPath
options:(NSKeyValueObservingOptions)options
context:(void *)context

方法说明

作用对象:被监听对象

参数说明:

anObserver:监听者

keyPath:被监听的属性

options:监听选项

context:任意的额外数据(上下文数据)

参数解析:

options:监听选项,可以是NSKeyValueObservingOptions选项的组合。

typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
//提供属性新值(修改后的值)
NSKeyValueObservingOptionNew = 0x01, //提供属性旧值(修改前的值)
NSKeyValueObservingOptionOld = 0x02, //如果指定,则在添加观察者的时候立即发送一个通知给观察者,
// 并且是在注册观察者方法返回之前
NSKeyValueObservingOptionInitial = 0x04, // 如果指定,则在每次修改属性时,会在修改通知被发送之前预先发送一条通知给观察者,
// 这与-willChangeValueForKey:被触发的时间是相对应的。
// 这样,在每次修改属性时,实际上是会发送两条通知。
NSKeyValueObservingOptionPrior = 0x08
};

context:可以将这些数据作为上下文数据,它会传递给观察者对象的observeValueForKeyPath:ofObject:change:context:方法。这个参数的意义在于用于区分同一对象监听同一属性(从属于同一对象)的多个不同的监听。(监听不会覆盖,只会并存)

2.删除指定key路径的监听器

- (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context

方法说明

作用对象:被监听对象

参数说明:

anObserver:监听者

keyPath:监听属性

context:上下文数据,与注册监听方法中的context对应。

3.监听回调

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

方法说明:

使用:重写该方法

参数说明:

keyPath:监听属性

object:监听对象(keyPath所属的对象)

change:监听属性的变化(字典类型)

context:数据上下文,从注册监听方法中传过来

参数解析:

change:记录监听属性的变化

// 属性变化的类型,是一个NSNumber对象,包含NSKeyValueChange枚举相关的值
NSString *const NSKeyValueChangeKindKey; // 属性的新值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionNew时,我们能获取到属性的新值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeInsertion或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionNew时,则我们能获取到一个NSArray对象,包含被插入的对象或
// 用于替换其它对象的对象。
NSString *const NSKeyValueChangeNewKey;
// 属性的旧值。当NSKeyValueChangeKindKey是 NSKeyValueChangeSetting,
// 且添加观察的方法设置了NSKeyValueObservingOptionOld时,我们能获取到属性的旧值。
// 如果NSKeyValueChangeKindKey是NSKeyValueChangeRemoval或者NSKeyValueChangeReplacement,
// 且指定了NSKeyValueObservingOptionOld时,则我们能获取到一个NSArray对象,包含被移除的对象或
// 被替换的对象。
NSString *const NSKeyValueChangeOldKey;
// 如果NSKeyValueChangeKindKey的值是NSKeyValueChangeInsertion、NSKeyValueChangeRemoval
// 或者NSKeyValueChangeReplacement,则这个key对应的值是一个NSIndexSet对象,
// 包含了被插入、移除或替换的对象的索引
NSString *const NSKeyValueChangeIndexesKey; // 当指定了NSKeyValueObservingOptionPrior选项时,在属性被修改的通知发送前,
// 会先发送一条通知给观察者。我们可以使用NSKeyValueChangeNotificationIsPriorKey
// 来获取到通知是否是预先发送的,如果是,获取到的值总是@(YES)
NSString *const NSKeyValueChangeNotificationIsPriorKey;

手动发送通知

  KVO是怎么做到对对象属性值的监听的呢? NSObject提供了一个NSKeyValueObserving协议的默认实现,这个协议使得对象属性在修改时具备了发送通知的能力。 当一个对象的属性发生修改时,KVO会调用下面两个方法发送修改通知。一旦修改的属性被监听,通知就会发送给监听者。

  理论上,子类不应该重写这两个方法,若要重写一定要在方法中调用父类的该方法,否则修改消息不会发送给监听者。但是如果只是监听自身的某个属性,则可以直接在这两个方法中对属性值的改变做出需要的响应,而不需要继续将消息发送出去,这时候无须为属性注册监听者。

//即将改变(值还未改变)
- (void)willChangeValueForKey:(NSString *)key{
NSLog(@"%@",key);
} //已经改变
- (void)didChangeValueForKey:(NSString *)key{
NSLog(@"%@",key);
}

这两个方法是KVO在对象属性值发生修改时发送通知的,默认情况下属性值改变会默认调用这两个方法发送通知。为提高灵活性,我们也可以手动发送通知。如果想对某个对象属性设置不自动发送值改变时的通知,重写下面方法

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key

判断key是否是对应对象属性名,是的话返回NO,这样就取消了这个对象属性自动发送修改通知的能力。

注意:

1.对于不是目标属性名的key,调用super的该方法,避免对其他属性的处理方法做了意外的修改。

2.设置了手动通知之后,只需在需要的地方视情况手动调用那两个发送通知的方法即可。

被监听对象依赖于别的属性

  假如要监听一个属性,这个属性的值依赖于其他若干个属性,这个属性称为计算属性,被依赖的属性中任意一个值发生变化都会导致计算属性的值改变。对于这种情况,一个做法是放弃计算属性,转而对被依赖的每个属性设置监听,然而这种方法会使情况变得复杂。这里KVO提供了更好的处理方法。

  首先设置好计算属性与依赖属性之间的依赖关系,这个依赖关系在计算属性的getter方法中体现,暂不知道还有没有什么别的设置依赖关系的方法。

//建立依赖关系(viewColor计算属性依赖于rColor、gColor、bColor)

- (UIColor *)viewColor{
return [UIColor colorWithRed:self.rColor/255.0 green:self.gColor/255.0 blue:self.bColor/255.0 alpha:1.0];
}

设置好依赖关系之后,要做的就是告诉KVO这个依赖关系的存在,重写方法:

+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key

在key为依赖属性名的情况下返回一个包含了依赖属性名的集合对象。也可以直接对依赖属性作用方法(以viewColor为例):

+ (NSSet *)keyPathsForValuesAffectingViewColor 

做好这些准备工作之后就可以像正常一样对计算属性设置监听了,当任意一个依赖属性值发生改变时,重写了监听回调方法的监听者就会收到通知。

对集合属性的监听

对于数组、集合这样的集合对象,若是不可变的,我们只能将其当做一个整体来监听,不需要做什么特别处理。若是可变的,我们也将其看成是一个整体,但若想监听到内容的添加、删除、替换,需要用集合代理对象来处理。

以可变数组为例,直接对数组本身设置监听者,然后添加数组内容,是不会触发通知发送的,因为数组本身是当成一个个体的,内存地址没有变。因此必需借助数组代理对象来实现,这个数组代理对象并不是简单得引用原数组对象,它可以理解成是原可变数组的一个替身,它可以替代原数组做任何原本能做的事,原数组内容也跟着它一起变。

之所以用代理数组对象可以实现对内容的监听,是因为对代理数组对象的内容添加、删除、替换后,原数组的内存地址发生了改变,这样就能发送通知了。

创建代理数组对象的方法:

- (NSMutableArray *)mutableArrayValueForKey:(NSString *)key;

该方法定义在KVC中。

对集合属性的监听也可以手动发送通知,做法和普通属性一样。发送通知方法为

-willChange:valuesAtIndexes:forKey:
-didChange:valuesAtIndexes:forKey:

KVO代码示例见Demo

参考文档:

http://www.cnblogs.com/kenshincui/p/3871178.html

http://southpeak.github.io/blog/2015/04/23/nskeyvalueobserving-kvo/

KVC/KVO总结的更多相关文章

  1. KVC/KVO原理详解及编程指南

    一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...

  2. 【转】 KVC/KVO原理详解及编程指南

    原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的 ...

  3. kvc/kvo复习

    kvc/kvo复习 1 小问题 '[<XMGPerson 0x7fb8a8f30220> setValue:forUndefinedKey:]: this XMGPerson * pers ...

  4. 转:KVC/KVO原理详解及编程指南

      作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或 ...

  5. 阶段性总结⓵触摸事件&手势识别⓶Quartz2D绘图⓷CALayer图层⓸CAAnimation⓹UIDynamic UI动力学⓺KVC&KVO

    知识点复习   1. 触摸事件&手势识别   1> 4个触摸事件,针对视图的 2> 6个手势识别(除了用代码添加,也可以用Storyboard添加)   附加在某一个特定视图上的, ...

  6. IOS开发之KVC KVO KVB

    KVC(Key Value Coding) KVO(Key Value Observing) KVB(Key Value Binding) KVO是Cocoa的一个重要机制,他提供了观察某一属性变化的 ...

  7. KVC & KVO

    KVC和KVO看上去又是两个挺牛的单词简写,KVC是Key-Value Coding的简写,是键值编码的意思.KVO是Key-Value  Observing的简写,是键值观察的意思.那么我们能拿KV ...

  8. KVC&&&KVO

    KVC 什么是KVC --->What KVC指的就是NSKeyValueCoding非正式协议. KVC是一种间接地访问对象的属性的机制. 这种间接表现在通过字符串来标识属性,而不是通过调用存 ...

  9. 04 KVC|KVO|Delegate|NSNotification区别

    一. iOS 中KVC.KVO.NSNotification.delegate 在实际的编程中运用的非常多,掌握好他们的运行原理和使用场合对于我们程序的开发将会带来事办工倍的效果:   二. KVC ...

  10. 深入理解 KVC\KVO 实现机制 — KVC

    KVC和KVO都属于键值编程而且底层实现机制都是isa-swizzing,所以本来想放在一起讲的.但是篇幅有限所以就分成了两篇博文 KVO实现机制传送门 KVC概述 KVC是Key Value Cod ...

随机推荐

  1. C字符串压缩算法

    #include <iostream> #include <stdlib.h> //#include <algorithm> using namespace std ...

  2. 我所经历的SAP选型

    这是一个失败的选型项目,而且在可遇见的未来公司也不会再经历SAP选型,甚至不会再启动erp项目,个中原因很难一言道尽,在此简要的说说我们的选型过程以及在选型过程中对各种因素的考虑. 一.重启选型工作七 ...

  3. linux对外开放某个端口命令

    /sbin/iptables -I INPUT -p tcp --dport 80 -j ACCEPT /etc/rc.d/init.d/iptables save /etc/rc.d/init.d/ ...

  4. Particle designer 粒子工具中属性对应功能的简单介绍

    粒子配置 Max Particles 粒子的数量  一般而言,我们的目标是用最少的粒子创造出所需的效果.单个粒子的大小对游戏运行效率也有很大的影响——单个粒子越小,性能越高. Lifespan 生命周 ...

  5. Haproxy图解

    http://blog.csdn.net/tantexian/article/details/50056199

  6. Ejection chain 与交错路

    相关文献: Rego, C. (1998). "A Subpath Ejection Method for the Vehicle Routing Problem." Manage ...

  7. mysql索引详解,摘自《MySQL 5权威指南》

    本文介绍了数据库索引,及其优.缺点.针对MySQL索引的特点.应用进行了详细的描述.分析了如何避免MySQL无法使用,如何使用EXPLAIN分析查询语句,如何优化MySQL索引的应用.本文摘自< ...

  8. Session fixation--wiki

    http://en.wikipedia.org/wiki/Session_fixation In computer network security, session fixation attacks ...

  9. JPA注释,内嵌数据对象

    @Data @Embeddable @NoArgsConstructor @AllArgsConstructor @JsonNaming(value = LowerCaseWithUnderscore ...

  10. jquery 实现图片跳动。提示作用

    需要做几件事: 第一:样式表定义 .red { border: 2px solid #ffffff; } 第二:定义抖动函数 function shake(ele, cls, times) { var ...