欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

IOS开发(39)之KVC KVO KVB

程序员文章站 2022-06-07 15:00:00
kvc(key value coding) kvo(key value observing) kvb(key value binding) kvo是cocoa的一个重要机制,...

kvc(key value coding)

kvo(key value observing)

kvb(key value binding)

kvo是cocoa的一个重要机制,他提供了观察某一属性变化的方法,极大的简化了代码。这种观察-被观察模型适用于这样的情况,比方说根据a(数 据类)的某个属性值变化,b(view类)中的某个属性做出相应变化。对于推崇mvc的cocoa而言,kvo应用的地方非常广泛。(这样的机制听起来类 似notification,但是notification是需要一个发送notification的对象,一般是 notificationcenter,来通知观察者。而kvo是直接通知到观察对象。)

when use kvo,it usually follows below:

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

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

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

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

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

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

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

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

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

新增加一个例子:点击下载

 

1 .person类
@implementation person @synthesize name,age;//属性name 将被监视
-(void) changename {     name=@"changename directly"; } @end   2.personmonitor类  监视了name属性 @implementation personmonitor  - (void)observevalueforkeypath:(nsstring *)keypath                       ofobject:(id)object                         change:(nsdictionary *)change                        context:(void *)context {     if ([keypath isequal:@"name"])     {         nslog(@"change happen, old:%@   new:%@",[change objectforkey:nskeyvaluechangeoldkey],[change objectforkey:nskeyvaluechangenewkey]);     } } @end   3测试代码     //初始化被监视对象     person *p =[[person alloc] init];    //监视对象    personmonitor *pm= [[personmonitor alloc]init];     [p addobserver:pm forkeypath:@"name" options:(nskeyvalueobservingoptionnew |nskeyvalueobservingoptionold) context:nil];    //测试前的数据     nslog(@"p.name is %@",p.name);     //通过setvalue 的方法,personmonitor的监视将被调用   [p setvalue:@"name kvc" forkey:@"name"];   //查看设置后的值    nslog(@"p name get by kvc is %@",[p valueforkey:@"name"]);  //效果和通过setvalue 是一致的     p.name=@"name change by .name=";   //通过person自己的函数来更改name       [p changename];    结果是 输出 2011-07-03 16:35:57.406 cocoa[13970:903] p.name is name 2011-07-03 16:35:57.418 cocoa[13970:903] change happen, old:name   new:name kvc 2011-07-03 16:35:57.420 cocoa[13970:903] p name get by kvc is name kvc 2011-07-03 16:35:57.421 cocoa[13970:903] change happen, old:name kvc   new:name change by .name= 最后一次修改是直接修改  所以没法产生通知 kvb
两个基本方法

1:为对象添加观察者observer

addobsever:forkeypath:options:context;

2:观察者observer收到信息的处理函数

obsevevalueforkeypath:ofobject:change:context;