KVC/KVO总结
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总结的更多相关文章
- KVC/KVO原理详解及编程指南
一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...
- 【转】 KVC/KVO原理详解及编程指南
原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的 ...
- kvc/kvo复习
kvc/kvo复习 1 小问题 '[<XMGPerson 0x7fb8a8f30220> setValue:forUndefinedKey:]: this XMGPerson * pers ...
- 转:KVC/KVO原理详解及编程指南
作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或 ...
- 阶段性总结⓵触摸事件&手势识别⓶Quartz2D绘图⓷CALayer图层⓸CAAnimation⓹UIDynamic UI动力学⓺KVC&KVO
知识点复习 1. 触摸事件&手势识别 1> 4个触摸事件,针对视图的 2> 6个手势识别(除了用代码添加,也可以用Storyboard添加) 附加在某一个特定视图上的, ...
- IOS开发之KVC KVO KVB
KVC(Key Value Coding) KVO(Key Value Observing) KVB(Key Value Binding) KVO是Cocoa的一个重要机制,他提供了观察某一属性变化的 ...
- KVC & KVO
KVC和KVO看上去又是两个挺牛的单词简写,KVC是Key-Value Coding的简写,是键值编码的意思.KVO是Key-Value Observing的简写,是键值观察的意思.那么我们能拿KV ...
- KVC&&&KVO
KVC 什么是KVC --->What KVC指的就是NSKeyValueCoding非正式协议. KVC是一种间接地访问对象的属性的机制. 这种间接表现在通过字符串来标识属性,而不是通过调用存 ...
- 04 KVC|KVO|Delegate|NSNotification区别
一. iOS 中KVC.KVO.NSNotification.delegate 在实际的编程中运用的非常多,掌握好他们的运行原理和使用场合对于我们程序的开发将会带来事办工倍的效果: 二. KVC ...
- 深入理解 KVC\KVO 实现机制 — KVC
KVC和KVO都属于键值编程而且底层实现机制都是isa-swizzing,所以本来想放在一起讲的.但是篇幅有限所以就分成了两篇博文 KVO实现机制传送门 KVC概述 KVC是Key Value Cod ...
随机推荐
- SQL 表锁(转)
其实你可以使用事务处理 比方说在一个字段里面添加一个boolean 的字段当你要处理该字段的时候就 True 哪么别的人都不可以进行操作 如果是False 哪么就可以进行操作--呵可--我是这样的 ...
- [Android][Android Studio] *.jar 与 *.aar 的生成与*.aar导入项目方法
主要讲解Android Studio中生成aar文件以及本地方式使用aar文件的方法. 在Android Studio中对一个自己库进行生成操作时将会同时生成*.jar与*.aar文件. 分别存储位置 ...
- VHD_Update_mount-vhd
###################功能说明########################该脚本用来对离线VHD文件更新,导入系统补丁############################### ...
- stm32上的Lava虚拟机开发进度汇报(1)
这几天我打算在stm32上做一个lava的虚拟机,只要160*80的黑白显示就行了,主要是想怀旧一下,嘿嘿. 目前的进度是图形显示和按键处理完成了,还有文本显示.文件处理.其他函数等. 当然,这都仅是 ...
- cocos2d-x如何优化内存的应用
自身以前也写过cocos2d-x如何优化内存的应用,以及内存不够的情况下怎么样处置惩罚游戏.今天在微博中看到有友好简介了下内存,挺详细的.不晓得是谁写的,我纪录下. 一,IOS与图片内存 在IOS上, ...
- WebFormJS注册位置
1. int height = Request.Browser.ScreenPixelsHeight; int width = Request.Browser.ScreenPixelsWidth; R ...
- Android Dalvik虚拟机初识(转)
原文地址:http://blog.csdn.net/andyxm/article/details/6126907 android虚拟机jvmjava优化linux内核 首先,让我们来思考下面几个问题: ...
- 合并js文件minify实例
将min目录放入项目中后,js中引入方式是: <script type="text/javascript" src="__PUBLIC__/min/?b=publi ...
- 5个可以帮你优化App的优秀网站
也许现在有一款App可以提供所有你需要的,你不需要的,或者你可以想象到的内容.但是,有多少App真的可以不仅满足需求而且还能提供很好的用户体验呢? 相信很多APP并没有这样的能力.有一些APP的设计特 ...
- X-Sequence
Description Let {xi} be the infinite sequence of integers: 1) x0 = A; 2) xi = (alpha * xi-1^2 + beta ...