Objective c  KVO/KVC做了简单的介绍_技术成长笔记_新浪博客

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得知发生了哪种变化,从而进行相应的处理。


 

 
 

  1. 1 .person类 
  2. @implementation Person 
  3. @synthesize name,age;//属性name 将被监视 
  4. -(void) changeName 
  5.     name=@"changeName directly"
  6. @end 
  7.  
  8.  
  9. 2.PersonMonitor类  监视了name属性 
  10. @implementation PersonMonitor 
  11.  
  12. - (void)observeValueForKeyPath:(NSString *)keyPath 
  13.                       ofObject:(id)object 
  14.                         change:(NSDictionary *)change 
  15.                        context:(void *)context 
  16.     if ([keyPath isEqual:@"name"]) 
  17.     { 
  18.         NSLog(@"change happen, old:%@   new:%@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]); 
  19.     } 
  20. @end 
  21.  
  22.  
  23. 3测试代码 
  24.  
  25.    //初始化被监视对象 
  26.     Person *p =[[Person alloc] init]; 
  27.    //监视对象 
  28.    PersonMonitor *pm= [[PersonMonitor alloc]init]; 
  29.     [p addObserver:pm forKeyPath:@"name" options:(NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld) context:nil]; 
  30.    
  31. //测试前的数据 
  32.     NSLog(@"p.name is %@",p.name); 
  33.     
  34. //通过setvalue 的方法,PersonMonitor的监视将被调用 
  35.   [p setValue:@"name kvc" forKey:@"name"]; 
  36.   
  37. //查看设置后的值 
  38.    NSLog(@"p name get by kvc is %@",[p valueForKey:@"name"]); 
  39.  
  40. //效果和通过setValue 是一致的     
  41. p.name=@"name change by .name="
  42.  
  43.  //通过person自己的函数来更改name  
  44.      [p changeName];  
  45.  
  46.  结果是 
  47. 输出 
  48. 2011-07-03 16:35:57.406 Cocoa[13970:903] p.name is name 
  49. 2011-07-03 16:35:57.418 Cocoa[13970:903] change happen, old:name   new:name kvc 
  50. 2011-07-03 16:35:57.420 Cocoa[13970:903] p name get by kvc is name kvc 
  51. 2011-07-03 16:35:57.421 Cocoa[13970:903] change happen, old:name kvc   new:name change by .name= 
  52. 最后一次修改是直接修改  所以没法产生通知 

 

二    分析

 2.1概念简述

        访问一个对象属性我们可以 person.name  也可以通过kvc的方式   [person valueForKey:@"name"]

    kvc  是  Key Value Coding   的缩写,这种机制引入的原因大概是“MVC with less code”

     kvo 就是一个在语言框架层面实现的观察者模式 通过kvc的方式修改属性时,会主动通知观察者

最后一个是直接修改数据不是kvc 模式修改数据,所以不会检测到数据的变化,即打印出数据的变化。

2.2问题

 
  
  • 1 p.name=@"name change by .name=";

         不是一个kvc 模式,为什么他也会监测?

      2  [p setValue:@"name kvc" forKey:@"name"]; 

       设置的key 是局部的还是全局的,就像那个[NSUserdefaulr  Standdefuler]那样的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值