Objective-C KVO的简单概述和示例

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

when use KVO,it usually follows below:

1 注册:

1
- (void)addObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context

keyPath就是要观察的属性值,options给你观察键值变化的选择,而context方便传输你需要的数据(注意这是一个void型)

2 实现变化方法:

1
2
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object
change:(NSDictionary *)change context:(void*)context

change里存储了一些变化的数据,比如变化前的数据,变化后的数据;如果注册时context不为空,这里context就能接收到。

是不是很简单?kvo的逻辑非常清晰,实现步骤简单。

说了这么多,大家都要跃跃欲试了吧。可是,在此之前,我们还需要了解KVC机制。看看这篇文章的使用-Object-C KVC的简单概述和示例


演示一个实例看看:

创建两个类Child和Nurse

Child.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//
// Child.h
// KVODemo
//
// Created by Durban on 13-12-19.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Child : NSObject

@property (nonatomic,assign) NSInteger happyVal;

@end

Child.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
//
// Child.m
// KVODemo
//
// Created by Durban on 13-12-19.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "Child.h"

@implementation Child

-(id) init
{
self = [super init];
if(self != nil)
{
_happyVal = 100;
[NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:@selector(timerAction:)
userInfo:nil
repeats:YES];
}

return self;
}

-(void) timerAction:(NSTimer *)timer
{
self.happyVal--;//必须使用点语法
//第二种语法
// _happyVal--;
// [self setValue:[NSNumber numberWithInteger:_happyVal] forKey:@"happyVal"];
}

@end

Nurse.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//
// Nurse.h
// KVODemo
//
// Created by Durban on 13-12-19.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>

@class Child;
@interface Nurse : NSObject

@property (nonatomic, retain) Child *child;
-(id) initWithChild:(Child *)child;

@end

Nurse.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
//
// Nurse.m
// KVODemo
//
// Created by Durban on 13-12-19.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import "Nurse.h"
#import "Child.h"

@implementation Nurse
@synthesize child = _child;

-(id) initWithChild:(Child *)child
{
self = [super init];
if(self != nil)
{
_child = child;
[_child addObserver:self
forKeyPath:@"happyVal"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:@"xx"];
}

return self;
}

-(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
NSLog(@"change = %@",change);
}

@end

测试实现过程如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
//
// main.m
// KVODemo
//
// Created by Durban on 13-12-19.
// Copyright (c) 2013年 WalkerFree. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Child.h"
#import "Nurse.h"

int main(int argc, const char * argv[])
{

@autoreleasepool {
Child *child = [[Child alloc] init];
Nurse *nurse = [[Nurse alloc] initWithChild:child];
[[NSRunLoop currentRunLoop] run];
// insert code here...
NSLog(@"Hello, World!");

}
return 0;
}

得到的结果是:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
2013-12-19 10:58:58.364 KVODemo[36662:303] change = {
kind = 1;
new = 99;
old = 100;
}
2013-12-19 10:58:59.359 KVODemo[36662:303] change = {
kind = 1;
new = 98;
old = 99;
}
2013-12-19 10:59:00.359 KVODemo[36662:303] change = {
kind = 1;
new = 97;
old = 98;
}
2013-12-19 10:59:01.358 KVODemo[36662:303] change = {
kind = 1;
new = 96;
old = 97;
}
Program ended with exit code: 9

如果得到如上的结果,说明使用是正确的


参考文章:

http://blog.csdn.net/weiwangchao_/article/details/7454968