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. cocos2d-x的初步学习二十一之iosandroid跨平台环境配置

    这篇文章中,我们将来构建下跨平台开发的环境配置,我自己也是参考了别人了文章,折腾了几个小时,尤其是android的配置相对麻烦些.... 参考自子龙山人:http://www.cnblogs.com/ ...

  2. eclipse/MyEclipse 日期格式、注释日期格式、时区问题[转]

    http://www.cnblogs.com/hoojo/archive/2011/03/21/1990070.html 在eclipse/MyEclipse中,如果你的注释或是运行System.ou ...

  3. 配置文件struts2Struts2配置文件模块化包含(include)与action总结

    本文是一篇关于配置文件struts2的帖子 <include>标签 当Struts配置文件比较多,需要模块化分别或分开成为多个配置文件时,这个功能比较好. 则需要使用<include ...

  4. 关于C++与Java中虚函数问题的读书笔记

    之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...

  5. 【M16】谨记80-20法则

    1.开始编写代码时,不要过多考虑效率,而应该首先考虑逻辑的清晰性和代码的可读性. 2.后期通过测试找到效率的瓶颈所在,而不是靠猜测.然后,针对性地去解决.也就是80%的时间去解决这20%的代码.

  6. Codeforces Round #330 (Div. 2) A. Vitaly and Night 暴力

    A. Vitaly and Night Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/595/p ...

  7. Nginx 1.4.7图片缓存服务器

    软件包版本: Nginx 1.4.7 Ngx_cache_purge-2.0 Openssl-1.0.1 Pcre-8.32 二.安装编译: a)         下载pcre-8.32.tar.gz ...

  8. android139 360 黑名单 增删改查-数据库操作

    BlackNumberOpenHelper.java package com.itheima52.mobilesafe.db.dao; import android.content.Context; ...

  9. Python拼接多张图片

    写机器学习相关博文,经常会碰到很多公式,而Latex正式编辑公式的利器.目前国内常用的博客系统,好像只有博客园支持,所以当初选择落户博客园.我现在基本都是用Latex写博文,然后要发表到博客园上与大家 ...

  10. vim中光标的前进和后退

    流行的文本编辑器通常都有前进和后退功能,可以在文件中曾经浏览过的位置之间来回移动.在 vim 中使用 Ctrl-O 执行后退,使用 Ctrl-I 执行前进.相关帮助: :help CTRL-O  :h ...