KVC & KVO 入门
KVC:
简介:
全称 Key-Value Coding 。KVC是一种间接访问对象属性(用字符串表征)的机制,而不是直接调用对象的accessor(setter/getter)方法或是直接访问成员对象。KVC的key值必需小写,并且必须是对象内的属性或变量。可以访问一些没有暴露出来的变量。
使用:
[_bank setValue:@"I am Lee" forKey:@"name"]; // 设置值 [_bank valueForKey:@"name"]; //读取值
可以看出KVC的使用是非常简单的,但是只有KVC是不够的,还需要结合KVO来做。
KVO:
简介:
当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。主要使用KVO来实现对象属性和变量的监听。当有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。总的来说,就是不需要自己去定义消息的通知机制,只需关心对象的值的变化。
使用:
定义Bank.h文件
// // Bank.h // testDemo // // Created by stardust on 15-1-15. // Copyright (c) 2015年 com. All rights reserved. // #import <Foundation/Foundation.h> @interface Bank : NSObject { NSString *name; } @property NSInteger money; -(void)beRobbed; @end
Bank.m文件:
// // Bank.m // testDemo // // Created by stardust on 15-1-15. // Copyright (c) 2015年 com. All rights reserved. // #import "Bank.h" @implementation Bank //@synthesize money; -(void)beRobbed{ self.money = self.money - 100; } @end
APerson.h文件:
// // APeron.h // testDemo // // Created by stardust on 15-1-15. // Copyright (c) 2015年 com. All rights reserved. // #import <Foundation/Foundation.h> @interface APeron : NSObject @end
APerson.m文件:
// // APeron.m // testDemo // // Created by stardust on 15-1-15. // Copyright (c) 2015年 com. All rights reserved. // #import "APeron.h" @implementation APeron -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ if ([keyPath isEqualToString:@"name"]) { NSLog(@"KVC old name is %@ , new name is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]); } else if([keyPath isEqualToString:@"money"]){ NSLog(@"KVC old money is %@ , new money is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]); } else{ NSLog(@"KVC old value is %@ , new value is %@",[change objectForKey:NSKeyValueChangeOldKey],[change objectForKey:NSKeyValueChangeNewKey]); } } @end
主文件KVOController.m:
// // KVOViewController.m // testDemo // // Created by stardust on 15-1-15. // Copyright (c) 2015年 com. All rights reserved. // #import "KVOViewController.h" #import "Bank.h" #import "APeron.h" @interface KVOViewController () @property APeron *aperson; @property Bank *bank; @end @implementation KVOViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view. _aperson = [[APeron alloc]init]; _bank = [[Bank alloc]init]; [_bank addObserver:_aperson forKeyPath:@"name" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:@"hello"]; [_bank addObserver:_aperson forKeyPath:@"money" options:(NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld) context:@"hello2"]; [_bank addObserver:_aperson forKeyPath:@"jack" options:(NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew) context:@"hello3"]; [_bank setValue:@"I am Lee" forKey:@"name"]; _bank.money = 101; [_bank beRobbed]; NSLog(@"... %@",[_bank valueForKey:@"name"]); //[_bank setValue:@"Tim Jack" forKey:@"jack"]; // 此句报错
// 一定要移除kvo,不然会有可能报错
[_bank removeObserver:_aperson forKeyPath:@"name"];
[_bank removeObserver:_aperson forKeyPath:@"money"];
[_bank removeObserver:_aperson forKeyPath:@"jack"];
} - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } /* #pragma mark - Navigation // In a storyboard-based application, you will often want to do a little preparation before navigation - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender { // Get the new view controller using [segue destinationViewController]. // Pass the selected object to the new view controller. } */ @end
显示结果:
2015-01-15 19:36:52.256 testDemo[3442:634253] KVC old name is <null> , new name is I am Lee 2015-01-15 19:36:52.257 testDemo[3442:634253] KVC old money is 0 , new money is 101 2015-01-15 19:36:52.257 testDemo[3442:634253] KVC old money is 101 , new money is 1 2015-01-15 19:36:52.258 testDemo[3442:634253] ... I am Lee
通过以上可以看出,设置aperson来监听Bank对象的变化,监听变化的处理放在APerson中,只要Bank对象中被监听的值发生变化,无论是直接设置改变,还是通过KVC,都能监听得到并执行相关监听的逻辑。但是,对于不存在的值,例如主文件代码中注释了的这句:” [_bank setValue:@"Tim Jack" forKey:@"jack"];“,即使可以添加不存在值的监听,但是调用相应的KVC时,会crash,这可能跟KVC的机制有关。
参考: