键值观察:值更改时通知观察者

键值观察(Key-value observing,或简称 KVO)允许对象观察另一个对象的属性。该属性值改变时,会通知观察对象。它了解新值以及旧值;如果观察的属性为对多的关系(例如数组),它也要了解哪个包含的对象发生了改变。KVO 有助于使应用程序变得更内聚,保持模型、控制器和视图层中的对象与改变同步。

与 NSNotificationCenter 通知相似,多个 KVO 观察者可以观察单一属性。此外,KVO 更动态,因为它允许对象观察任意属性,而不需任何新的 API,例如通知名称。KVO 是一个轻量级点对点通信机制,不允许观察所有实例的特定属性。

----以上解释来着官方文档----

Key-Value Observing机制的概述

Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。

KVO的优点

当有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。

KVO如何工作

需要三个步骤来建立一个属性的观察员。理解这三个步骤就可以知道KVO如何设计工作的。

(1)首先,构思一下如下实现KVO是否有必要。比如,一个对象,当另一个对象的特定属性改变的时候,需要被通知到。

例如,PersonObject希望能够觉察到BankObject对象的accountBalance属性的任何变化。

(2)那么PersonObject必须发送一个“addObserver:forKeyPath:options:context:”消息,注册成为BankObject的accountBalance属性的观察者。

(说明:“addObserver:forKeyPath:options:context:”方法在指定对象实例之间建立了一个连接。注意,这个连接不是两个类之间建立的,而是两个对象实例之间建立的。)

(3)为了能够响应消息,观察者必须实现“observeValueForKeyPath:ofObject:change:context:”方法。这个方法实现如何响应变化的消息。在这个方法里面我们可以跟自己的情况,去实现应对被观察对象属性变动的相应逻辑。

(4)假如遵循KVO规则的话,当被观察的属性改变的话,方法“observeValueForKeyPath:ofObject:change:context:”会自动被调用。

KVO是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。

适用kvo时,通常遵循如下流程:

1 注册:

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

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)

2 实现变化方法:

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

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

是不是很简单?kvo的逻辑非常清晰,实现步骤简单。

说了这么多,大家都要跃跃欲试了吧。可是,在此之前,我们还需要了解KVC机制。其实,知道了kvo的逻辑只是帮助你理解而已,要真正掌握的,不在于kvo的实现步骤是什么,而在于KVC,因为只有符合KVC标准的对象才能使用kvo(强烈推荐要使用kvo的人先理解KVC)。

KVC--Key - value coding 机制

KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor方法或是直接访问成员对象。

key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名,并且必须以小写字母开头。

Key path就是以“.”分隔的key,property can be object whick also contains property。比如我们可以person这样的key,也可以有key.gender这样的key path。

(setValue:forKey,valueForKey:)、(setValue:forKeyPath,valueForKeyPath:)

获取属性值时可以通过valueForKey:的方法,设置属性值用setValue:forKey:。与此同时,KVC还对未定义的属性值定义了 valueForUndefinedKey:,你可以重载以获取你要的实现(补充下,KVC定义载NSKeyValueCoding的非正式协议里)。

在O-C 2.0引入了property,我们也可以通过 .(点)运算符来访问属性。下面直接看个例子:

@property NSInteger number;

instance.number 
=
3
;
[instance setValue:[NSNumber numberWithInteger:
3
] forKey:
@"
number
"
];

注意KVC中的value都必须是对象。

下面举个例子解释一下KVC:

1.先定义两数据模型,下面的这两个model是无法直接访问属性的。

@interface BookData : NSObject {
NSString * bookName;
float price;
AuthorData * author;
}
@end
@implementation BookData
@end
@interface AuthorData : NSObject {
NSString * name;
}
@end
@implementation AuthorData
@end

使用KVC

AuthorData * author1 = [[AuthorData alloc] init];
[author1 setValue:@"tom" forKey:@"name"];
BookData * book1 = [[BookData alloc] init];
[book1 setValue:@"english" forKey:@"bookName"];
[book1 setValue:@"20.0" forKey:@"price"];
[book1 setValue:author1 forKey:@"author"]; NSLog(@"value=%@",[book1 valueForKey:@"bookName"]);
NSLog(@"price=%f",[[book1 valueForKey:@"price"] floatValue]);
NSLog(@"author=%@",[book1 valueForKeyPath:@"author.name"]);

下面举一个例子解释一下 KVO

Person.h

#import <Foundation/Foundation.h>

@interface Person : NSObject

@property(nonatomic,retain)NSString *name;
@property(nonatomic,assign)NSInteger age; -(void)changeName; @end

Person.m

#import "Person.h"

@implementation Person

@synthesize name,age;//属性name将被监视

-(void)changeName
{
name=@"changeName directly";
} @end

PersonMonitor.h

#import <Foundation/Foundation.h>

@interface PersonMonitor : NSObject

@end

PersonMonitor.m

#import "PersonMonitor.h"

@implementation PersonMonitor

//观察者需要实现的方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqual:@"name"])
{
NSLog(@"change happen,old:%@ ,new:%@;context = %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey],context);
}
} @end

main.m

#import <Foundation/Foundation.h>
#import "Person.h"
#import "PersonMonitor.h" int main(int argc, const char * argv[])
{ @autoreleasepool { //测试代码
//监视对象
Person *p =[[Person alloc] init]; //观察者对象
PersonMonitor *pm= [[PersonMonitor alloc]init]; //Observer KVO收到通知指定的关键路径相对于接收器。
/*
*pm 对象注册KVO通知。观察者必须实现键值观察方法observeValueForKeyPath。
*forKeyPath 关键路径,相对于接收器,用于观察的属性。这个值不能为零。
*options NSKeyValueObservingOptions的组合值,指定包含在观察通知的内容。
*context 任意的数据传递给anObserver在observeValueForKeyPath。
*/ [p addObserver:pm forKeyPath:@"name" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"hello world"]; //测试前的数据
NSLog(@"p.name is %@",p.name); //通过setvalue 的方法,PersonMonitor的监视将被调用
[p setValue:@"name kvc" forKey:@"name"]; //查看设置后的值
NSLog(@"p.name is %@",[p valueForKey:@"name"]); //效果和通过setValue 是一致的
p.name=@"name change by .name"; //通过person自己的函数来更改 name
[p changeName];
//最后一次修改是直接修改,所以没法产生通知。只有当我们调用KVC去访问key值的时候KVO才会起作用
NSLog(@"p.name is %@",p.name); //删除观察者
// [p removeObserver:pm forKeyPath:@"name"]; }
return 0;
}

终端输出结果:

2013-07-19 11:04:17.946 KVC_KVOTest[1187:303] p.name is (null)

2013-07-19 11:04:17.948 KVC_KVOTest[1187:303] change happen,old:<null> ,new:name kvc;context = hello world

2013-07-19 11:04:17.949 KVC_KVOTest[1187:303] p.name is name kvc

2013-07-19 11:04:17.949 KVC_KVOTest[1187:303] change happen,old:name kvc ,new:name change by .name;context = hello world

2013-07-19 11:04:17.950 KVC_KVOTest[1187:303] p.name is changeName directly

刚接触KVO  KVC 所以只是懂了个大概,以后还是要通过实践应用才更深入的理解。

注明:以上内容基本上参考了其他博友的文章和例子,这里整合了。

iOS KVO & KVC的更多相关文章

  1. iOS:KVO/KVC 的概述与使用

    iOS:KVO/KVC 的概述与使用       KVO   APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性 ...

  2. 【转】 iOS KVO KVC

    原文: http://www.cocoachina.com/industry/20140224/7866.html Key Value Coding Key Value Coding是cocoa的一个 ...

  3. 【iOS】KVC 与 KVO

    一.KVC与KVO *"KVC":key value Coding(键值编码) *目的:间接的改动或获取对象的属性,减少程序(类与类)之间的耦合度. *"KVO" ...

  4. IOS之KVC和KVO(未完待续)

    *:first-child { margin-top: 0 !important; } body > *:last-child { margin-bottom: 0 !important; } ...

  5. KVO/KVC总结

    KVO/KVC总结       下面是根据网上文章的总结,方便查看. 在网上看别人的文章,了解KVC.KVO,有个kvo-kvc的例子,就是改变数组的内容(插入和删除),同步改变tableview中的 ...

  6. iOS KVO概述

    iOS KVO概述 面试中经常会被问到:什么是KVO?这个问题既然出现概率这么大,那么我们就来详细讲一讲到底什么是KVO.下次再有面试官问你的时候,你就可以娓娓道来,以彰显高逼格 概述 问:什么是KV ...

  7. iOS kvo 结合 FBKVOController 的使用

    iOS kvo 结合 FBKVOController 的使用 一:FBKVOControlloer是FaceBook开源的一个 在 iOS,maxOS上使用 kvo的 开源库: 提供了block和@s ...

  8. 【原】iOS中KVC和KVO的区别

    在iOS开发中经常会看到KVC和KVO这两个概念,比较可能混淆,特地区分一下 KVC(Key Value Coding) 1> 概述 KVC:Key Value Coding,键值编码,是一种间 ...

  9. iOS 中KVC、KVO、NSNotification、delegate 总结及区别-b

    1.KVC,即是指 NSKeyValueCoding,一个非正式的Protocol,提供一种机制来间接访问对象的属性.而不是通过调用Setter.Getter方法访问.KVO 就是基于 KVC 实现的 ...

随机推荐

  1. vs2010 项目编译 ResGen.exe”已退出,代码为 -1073741701

    解决的办法如下: 1.关闭所有Visual Studio: 2.以管理员的身份打开命令提示窗口:(开始-运行-cmd) 3.更改目录至"CD C:\Program Files (x86)\M ...

  2. C++之构造函数重载

    #include<stdio.h> class Test    {        private:         int i;         int j;         int k; ...

  3. LOJ 1370 Bi-shoe and Phi-shoe(欧拉函数的简单应用)

    题目链接:http://lightoj.com/volume_showproblem.php?problem=1370 题意:给你n个整数,第i个整数为Xi.定义phi(k)为k的欧拉函数值,设pi为 ...

  4. Hibernate学习之映射关系

    一.Hibernate多对一关联映射:就是在“多”的一端加外键,指向“一”的一端. 比如多个学生对应一个班级,多个用户对应一个级别等等,都是多对一关系. 1.“多”端实体加入引用“一”端实体的变量及g ...

  5. php基础教程笔记2

    如果学过c.java,php的语法不学即会,但是不同的是php是一种脚本语言,需要解释器才能运行.php又和js不同,js是客户端语言,而php运行在服务器端,它无法获取客户端浏览器信息.但是php又 ...

  6. python自学笔记(七)排序与多级排序

    一.sorted内置方法 a = [1,2,3,4] 从大到小(翻转) a = sorted(a,reverse = True) #生成新对象,不会原地修改,需要重新赋值 print a --> ...

  7. w3wp.exe CPU过百问题

    w3wp.exe CPU过百问题 最近发布在windows  server2012  IIS8.0上的一个WebAPI项目,才几十个人在线,CPU就会出现过百情况,并且CPU一旦过百应用程序池就自动暂 ...

  8. 转:在控制台中调试AngularJS应用

    在控制台中调试AngularJS应用 在创建AngularJS应用时,一个很棘手的问题是如何在Chrome,Firefox,以及IE的JavaScript控制台中访问深藏在应用中的数据和服务.本文将会 ...

  9. Wmic-linux

    Description Windows Management Instrumentation Command-line (WMIC) uses Windows Management Instrumen ...

  10. C#共享内存类改进版

    原文 C#共享内存类改进版 改进说明及源码实例下载见:http://blog.csdn.net/zzh8845/archive/2008/11/22/3349963.aspx ShareMem.cs ...