原文链接:http://www.verydemo.com/demo_c134_i5320.html
(文章末尾有惊喜!)
1、什么是KVO?
Key-Value-Observing(KVO,键值观察):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
2、KVO有什么优点?
当有属性改变,KVO会提供自动的消息通知。
3、KVO实现
1)注册观察者(Registering as an Observer),指定被观察的属性。
addObserver:forKeyPath:options:context:
2)接收变化通知(Receiving Notification of a Change),实现回调方法。
observeValueForKeyPath:ofObject:change:context:
3)移除观察者(Removing an Object as an Observer)
removeObserver:forKeyPath:
4、简单示例
1)创建一个简单的SingleView模板的iPhone应用,我取名为KVODemo。
2)在界面添加一个label和一个button,并生成相应的outlet。
下面ViewConroller.h和ViewConroller.m
ViewConroller.h源码清单:
#import <UIKit/UIKit.h>
@interface ViewController : UIViewController
@property (retain,nonatomic) IBOutlet UILabel *label;
- (IBAction)buttonPressed:(UIButton *)sender;
@end
ViewConroller.m源码清单:
#import "ViewController.h"
@interface ViewController (){
NSString *_str;
}
@property (nonatomic,retain) NSString *str;
@end
@implementation ViewController
@synthesize label=_label;
@synthesize str=_str;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
_str =@"sharon";
_label.text = _str;
// 添加Observer 这样被注册的属性发生改变的时候Observer回调方法就被调用
[selfaddObserver: selfforKeyPath: @"str"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
}
- (IBAction)buttonPressed:(UIButton *)sender {
static BOOL flag =YES;
if (flag) {
// 修改正在监听的属性值
[selfsetValue: @"joe"forKey: @"str"];
}else {
// 修改正在监听的属性值
[selfsetValue: @"sharon"forKey: @"str"];
}
flag = !flag;
}
// 实现Observer的回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
// 如果改变的属性是"name"
if ([keyPath isEqualToString:@"str"]) {
_label.text = [self valueForKey:@"str"];
// 输出改变前的值
NSLog(@"old str is %@",[change objectForKey:@"old"]);
// 输出改变后的值
NSLog(@"new str is %@",[change objectForKey:@"new"]);
}
}
-(void)dealloc{
// 移除Observer
[self removeObserver:selfforKeyPath:@"str"];
[super dealloc];
}
@end
值得注意的是
1、执行顺序,当按键按下之后,执行这个方法的时候[self setValue: @"xxx"forKey: @"str"];
那么就已经开始执行- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 这个方法(这个方法是必须要实现的,否则会引起程序崩溃)
2、[selfaddObserver: selfforKeyPath: @"str"options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
options参数中的参数作用 决定了字典中是否有这两个键值的入口
/* Whether the change dictionaries sent in notifications should contain NSKeyValueChangeNewKey and NSKeyValueChangeOldKey entries, respectively.
*/
3、这个函数的作用
- (id)value |
知道了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还可以运用到对多关系,