KVO/KVC总结

KVO/KVC总结

下面是根据网上文章的总结,方便查看。

在网上看别人的文章,了解KVC、KVO,有个kvo-kvc的例子,就是改变数组的内容(插入和删除),同步改变tableview中的内容。运行了代码之后,想添加修改数组时改变tableview内容,但是一直不能调用观察函数,后来又查了点资料,原来,数组的kvc是都是有固定格式的函数名字。把改后的工程放到资源里面了。供大家下载。下面是拷贝过来的资料。

一.KVC和KVO的概念

1> KVC:NSKeyValueCoding的简称,是一种可以直接通过字符串的名字(key)来访问类属性的机制,而不是通过调用的Setter、Getter方法访问。

2> KVO:NSKeyValueObserving的简称,当指定的对象的属性被修改了,允许对象接收到通知的机制。

二.KVC介绍

1、概述

KVC是KeyValue Coding的简称,它是一种可以直接通过字符串的名字(key)来访问类属性的机制。而不是通过调用Setter、Getter方法访问。

当使用KVO、Core Data、CocoaBindings、AppleScript(Mac支持)时,KVC是关键技术。

2、如何使用KVC

关键方法定义在:NSKeyValueCodingprotocol

KVC支持类对象和内建基本数据类型。

获取值

valueForKey:,传入NSString属性的名字。

valueForKeyPath:,传入NSString属性的路径,xx.xx形式。

valueForUndefinedKey它的默认实现是抛出异常,可以重写这个函数做错误处理。

 修改值

setValue:forKey:

setValue:forKeyPath:

setValue:forUndefinedKey:

setNilValueForKey: 当对非类对象属性设置nil时,调用,默认抛出异常。

一对多关系成员的情况

mutableArrayValueForKey:有序一对多关系成员  NSArray

mutableSetValueForKey:无序一对多关系成员  NSSet

3、KVC的实现细节

搜索Setter、Getter方法

 这一部分比较重要,能让你了解到KVC调用之后,到底是怎样获取和设置类成员值的。

搜索简单的成员

如:基本类型成员,单个对象类型成员:NSInteger,NSString*成员。

a. setValue:forKey的搜索方式:

首先搜索set<Key>:方法

如果成员用@property,@synthsize处理,因为@synthsize告诉编译器自动生成set<Key>:格式的setter方法,所以这种情况下会直接搜索到。

注意:这里的<Key>是指成员名,而且首字母大写。下同。

上面的setter方法没有找到,如果类方法accessInstanceVariablesDirectly返回YES(注:这是NSKeyValueCodingCatogery中实现的类方法,默认实现为返回YES)。

那么按_<key>,_is<Key>,<key>,is<key>的顺序搜索成员名。

如果找到设置成员的值,如果没有调用setValue:forUndefinedKey:。

b. valueForKey:的搜索方式:

1. 首先按get<Key>、<key>、is<Key>的顺序查找getter方法,找到直接调用。如果是bool、int等内建值类型,会做NSNumber的转换。

2. 上面的getter没有找到,查找countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes格式的方法。

如果countOf<Key>和另外两个方法中的一个找到,那么就会返回一个可以响应NSArray所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSArray消息方法,就会以countOf<Key>、objectIn<Key>AtIndex:、<Key>AtIndexes这几个方法组合的形式调用。还有一个可选的get<Key>:range:方法。

3. 还没查到,那么查找countOf<Key>、enumeratorOf<Key>、memberOf<Key>:格式的方法。

如果这三个方法都找到,那么就返回一个可以响应NSSet所有方法的代理集合(collection proxy object)。发送给这个代理集合(collection proxy object)的NSSet消息方法,就会以countOf<Key>、enumeratorOf<Key>、memberOf<Key>:组合的形式调用。

4. 还是没查到,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,_is<Key>,<key>,is<key>的顺序直接搜索成员名。

5. 再没查到,调用valueForUndefinedKey:。

查找有序集合成员,比如NSMutableArray

mutableArrayValueForKey:搜索方式如下:

1. 搜索insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:或者insert<Key>:atIndexes、remove<Key>AtIndexes:格式的方法。

如果至少一个insert方法和至少一个remove方法找到,那么同样返回一个可以响应NSMutableArray所有方法的代理集合。那么发送给这个代理集合的NSMutableArray消息方法,以insertObject:in<Key>AtIndex:、removeObjectFrom<Key>AtIndex:、insert<Key>:atIndexes、remove<Key>AtIndexes:组合的形式调用。还有两个可选实现的接口:replaceObjectIn<Key>AtIndex:withObject:、replace<Key>AtIndexes:with<Key>:。

2. 否则,搜索set<Key>:格式的方法,如果找到,那么发送给代理集合的NSMutableArray最终都会调用set<Key>:方法。

也就是说,mutableArrayValueForKey取出的代理集合修改后,用set<Key>:重新赋值回去。这样做效率会差很多,所以推荐实现上面的方法。

3. 否则,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,<key>的顺序直接搜索成员名。如果找到,那么发送的NSMutableArray消息方法直接转交给这个成员处理。

4. 再找不到,调用setValue:forUndefinedKey:。

搜索无序集合成员,如:NSSet。

mutableSetValueForKey:搜索方式如下:

1. 搜索add<Key>Object:、remove<Key>Object:或者add<Key>:、remove<Key>:格式的方法,如果至少一个insert方法和至少一个remove方法找到,那么返回一个可以响应NSMutableSet所有方法的代理集合。那么发送给这个代理集合的NSMutableSet消息方法,以add<Key>Object:、remove<Key>Object:、add<Key>:、remove<Key>:组合的形式调用。还有两个可选实现的接口:intersect<Key>、set<Key>:。

2. 如果reciever是ManagedObejct,那么就不会继续搜索了。

3. 否则,搜索set<Key>:格式的方法,如果找到,那么发送给代理集合的NSMutableSet最终都会调用set<Key>:方法。也就是说,mutableSetValueForKey取出的代理集合修改后,用set<Key>:重新赋值回去。这样做效率会差很多,所以推荐实现上面的方法。

4. 否则,那么如果类方法accessInstanceVariablesDirectly返回YES,那么按_<key>,<key>的顺序直接搜索成员名。如果找到,那么发送的NSMutableSet消息方法直接转交给这个成员处理。

5. 再找不到,调用setValue:forUndefinedKey:。

KVC还提供了下面的功能

值的正确性核查

KVC提供属性值确认的API,它可以用来检查set的值是否正确、为不正确的值做一个替换值或者拒绝设置新值并返回错误原因。

实现核查方法

为如下格式:validate<Key>:error:

如:

-(BOOL)validateName:(id *)ioValue error:(NSError **)outError

{

// The name must not be nil, and must be at least two characters long.

if ((*ioValue == nil) || ([(NSString *)*ioValue length] < 2]) {

if (outError != NULL) {

NSString *errorString = NSLocalizedStringFromTable(

@"A Person‘s name must be at least two characters long", @"Person",

@"validation: too short name error");

NSDictionary *userInfoDict =

[NSDictionary dictionaryWithObject:errorString

forKey:NSLocalizedDescriptionKey];

*outError = [[[NSError alloc] initWithDomain:PERSON_ERROR_DOMAIN

code:PERSON_INVALID_NAME_CODE

userInfo:userInfoDict] autorelease];

}

return NO;

}

return YES;

}

调用核查方法:

validateValue:forKey:error:,默认实现会搜索 validate<Key>:error:格式的核查方法,找到则调用,未找到默认返回YES。

注意其中的内存管理问题。

集合操作

集合操作通过对valueForKeyPath:传递参数来使用,一定要用在集合(如:array)上,否则产生运行时刻错误。其格式如下:

Left keypath部分:需要操作对象路径。

Collectionoperator部分:通过@符号确定使用的集合操作。

Rightkey path部分:需要进行集合操作的属性。

1、数据操作

@avg:平均值

@count:总数

@max:最大

@min:最小

@sum:总数

确保操作的属性为数字类型,否则运行时刻错误。

2、对象操作

针对数组的情况

@distinctUnionOfObjects:返回指定属性去重后的值的数组

@unionOfObjects:返回指定属性的值的数组,不去重

属性的值不能为空,否则产生异常。

3、数组操作

针对数组的数组情况

@distinctUnionOfArrays:返回指定属性去重后的值的数组

@unionOfArrays:返回指定属性的值的数组,不去重

@distinctUnionOfSets:同上,只是返回值为NSSet

三.KVC实现分析

KVC运用了一个isa-swizzling技术。isa-swizzling就是类型混合指针机制。KVC主要通过isa- swizzling,来实现其内部查找定位的。isa指针,如其名称所指,(就是is a kind of的意思),指向维护分发表的对象的类。该分发表实际上包含了指向实现类中的方法的指针,和其它数据。

比如说如下的一行KVC的代码:

[site setValue:@"sitename" forKey:@"name"];

就会被编译器处理成:

SEL sel = sel_get_uid ("setValue:forKey:");
IMP method = objc_msg_lookup (site->isa,sel);
method(site, sel, @"sitename", @"name");

首先介绍两个基本概念:

(1)SEL数据类型:它是编译器运行Objective-C里的方法的环境参数。

(2)IMP数据类型:他其实就是一个 编译器内部实现时候的函数指针。当Objective-C编译器去处理实现一个方法的时候,就会指向一个IMP对象,这个对象是C语言表述的类型(事实 上,在Objective-C的编译器处理的时候,基本上都是C语言的)。

关于如何找到实现函数的指针,可参考文章:《Objective-C如何避免动态绑定,而获得方法地址》:http://www.cocoadev.cn/Objective-C/Get-method-address.asp

这下KVC内部的实现就很清楚的清楚了:一个对象在调用setValue的时候,(1)首先根据方法名找到运行方法的时候所需要的环境参数。(2)他会从自己isa指针结合环境参数,找到具体的方法实现的接口。(3)再直接查找得来的具体的方法实现。

四.KVO介绍

Kvo是Cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据A(数 据类)的某个属性值变化,B(view类)中的某个属性做出相应变化。对于推崇MVC的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类 似Notification,但是notification是需要一个发送notification的对象,一般是 notificationCenter,来通知观察者。而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是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor方法或是直接访问成员对象。

key就是确定对象某个值的字符串,它通常和accessor方法或是变量同名,并且必须以小写字母开头。Key path就是以“.”分隔的key,因为属性值也能包含属性。比如我们可以person这样的key,也可以有key.gender这样的key path。

获取属性值时可以通过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来获取/设置属性,接下来要说明下实现KVC的访问器方法(accessor method)。Apple给出的惯例通常是:

-key:,以及setKey:(使用的name convention和setter/getter命名一致)。对于未定义的属性可以用setNilValueForKey:。

至此,KVC的基本概念你应该已经掌握了。之所以是基本,因为只涉及到了单值情况,kvc还可以运用到对多关系,这里就不说了,留给各位自我学习的空间

接下来,我们要以集合为例,来对掌握的KVC进行一下实践。

之所以选择array,因为在ios中,array往往做为tableview的数据源,有这样的一种情况:

假设我们已经有N条数据,在进行了某个操作后,有在原先的数据后多了2条记录;或者对N中的某些数据进行更新替换。不使用KVC我们可以使用 reloadData方法或reloadRowsAtIndexPaths。前一种的弊端在于如果N很大消耗就很大。试想你只添加了几条数据却要重载之前 N数据。后一种方法的不足在于代码会很冗余,你要一次计算各个indexPath再去reload,而且还要提前想好究竟在哪些情况下会引起数据更新,

倘若使用了KVC/kvo,这样的麻烦就迎刃而解了,你将不用关心追加或是更新多少条数据。

下面将以添加数据为例,说明需要实现的方法:

实现insertObject:inKeyAtIndex:或者insertKey:atIndexes。同时在kvo中我们可以通过change这个dictionary得知发生了哪种变化,从而进行相应的处理。

时间: 2024-11-08 03:29:50

KVO/KVC总结的相关文章

iOS:KVO/KVC 的概述与使用

KVO   APP开发技术QQ群:347072638 一,概述 KVO,即:Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知.简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了. 二,使用方法 系统框架已经支持KVO,所以程序员在使用的时候非常简单. 1. 注册,指定被观察者的属性, 2. 实现回调方法 3. 移除观察 三,实例: 假设一个场景,股票的价格显示在当前屏幕上,当股票价格更改的时候,实时显示更新其

iOS开发——KVO/KVC&amp;OC与Swift篇详解

Swift中使用KVC和KVO的类都必须必须继承自NSObject KVC key-value coding 是1种间接访问对象的机制 key的值就是属性名称的字符串,返回的value是任意类型,需要自己转化为需要的类型 KVC主要就是两个方法 (1)通过key设置对应的属性 (2)通过key获得对应的属性 举例 class TestForKVC:NSObject{ var hwcCSDN = "hello world" } var instance = TestForKVC() va

ios 之kvo&amp;kvc的使用

转载:http://www.cnblogs.com/kenshincui/p/3871178.html 概述 由于ObjC主要基于Smalltalk进行设计,因此它有很多类似于Ruby.Python的动态特性,例如动态类型.动态加载.动态绑定等.今天我们着重介绍ObjC中的键值编码(KVC).键值监听(KVO)特性: 键值编码KVC 键值监听KVO 键值编码KVC 我们知道在C#中可以通过反射读写一个对象的属性,有时候这种方式特别方便,因为你可以利用字符串的方式去动态控制一个对象.其实由于Obj

KVO &amp;&amp; KVC

KVO: key-value observing 当指定的对象的属性被修改后,则对象就会接受到通知. 简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者. 使用步骤: 1.注册,指定被观察者的属性(由被观察者主动添加观察自己的观察者) 2.实现回调方法 3.移除观察 使用范例: @interface StockData : NSObject { NSString * stockName; float price; } @end @implementation Sto

kvo&amp;kvc

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

【转】 iOS KVO KVC

原文: http://www.cocoachina.com/industry/20140224/7866.html Key Value Coding Key Value Coding是cocoa的一个标准组成部分,它能让我们可以通过name(key)的方式访问property, 不必调用明确的property accssor, 如我们有个property叫做foo, 我们可以foo直接访问它,同样我们也 “” 阅读器 iOSKVOKVC 转自:Regrecall blogger Key Valu

KVO/KVC 实现机理分析

原文:http://blog.csdn.net/dqjyong/article/details/7672865 Objective-C里面的Key-Value Observing (KVO)机制,非常不错,可以很好的减少浇水代码.关于KVO的学习,可以参考文章:<Key-Value Observing快速入门>:http://www.cocoadev.cn/Objective-C/Key-Value-Observing-Quick-Start-cn.asp KVO概念:      KVO是co

细说KVO &amp; KVC &amp; NSNotificationCenter那些事

在iOS开发过程中,我们经常会听到或者用到KVO,KVC,NSNotificationCenter等,但是很多时候,我们可能没有那么了解,下面让我们来详细了解下他们的概念.用法以及他们之间的关系吧- 本篇博客共分以下几个模块来介绍: 什么是KVC? 什么是KVO? KVC与KVO的关系 KVC Collection Operators 什么是NSNotificationCenter? NSNotificationCenter与KVO的比较 NSNotificationCenter与Delegat

kvo kvc 知识点在IOS Developer Library中的位置

进入到Topics的Data Managment版块,搜索 key-value即可出来 KVC Data Management ->key-value Coding Programming Guide (Foundation Framework) KVO Data Management ->key-value Observing Programming Guide (Foundation Framework)