1.1 KVO的定义
KVO(Key-Value Observing),俗称键值监听。它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
1.2 KVO的使用
KVO的定义KVO是“观察者”设计模式的一种应用,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。这种模式有利于两个类间的解耦合,尤其是对于业务逻辑与视图控制 这两个功能的解耦合。和KVC类似,在ObjC中要实现KVO则必须实现NSKeyValueObServing协议,但不用担心,因为NSObject已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO.
1.3KVO常用的方法
1>注册指定Key路径的监听器
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context
相关参数:
observer:观察者,也就是KVO通知的订阅者。订阅着必须实现
observeValueForKeyPath:ofObject:change:context:方法
keyPath:描述将要观察的属性,相对于被观察者。
options:KVO的一些属性配置;有四个选项。
options所包括的内容:
NSKeyValueObservingOptionNew: change字典包括改变后的值
NSKeyValueObservingOptionOld: change字典包括改变前的值
NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知
NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)
context: 上下文,这个会传递到订阅着的函数中,用来区分消息,所以应当是不同的。
注意:不要忘记解除注册,否则会导致资源泄露
2>删除指定Key路径的监听器:
- (void)removeObserver:(NSObject *)anObserver forKeyPath:(NSString *)keyPath
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(void *)context
3>回调监听
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
keyPath:被监听的keyPath , 用来区分不同的KVO监听。
object: 被观察修改后的对象(可以通过object获得修改后的值)
change:保存信息改变的字典(可能有旧的值,新的值等)
context:上下文,用来区分不同的KVO监听
KVO的使用步骤也比较简单
1>注册,指定被观察者的属性
2> 实现回调方法
3>移除观察
1.4 KVO的使用场景
@interface StockData : NSObject {
NSString * stockName;
float price;
}
@end
@implementation StockData
@end
- (void)viewDidLoad
{
[super viewDidLoad];
stockForKVO = [[StockData alloc] init];
[stockForKVO setValue:@"searph" forKey:@"stockName"];
[stockForKVO setValue:@"10.0" forKey:@"price"];
[stockForKVO addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:NULL];
myLabel = [[UILabel alloc]initWithFrame:CGRectMake(100, 100, 100, 30 )];
myLabel.textColor = [UIColor redColor];
myLabel.text = [stockForKVO valueForKey:@"price"];
[self.view addSubview:myLabel];
UIButton * b = [UIButton buttonWithType:UIButtonTypeRoundedRect];
b.frame = CGRectMake(0, 0, 100, 30);
[b addTarget:self action:@selector(buttonAction) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:b];
}
-(void) buttonAction
{
[stockForKVO setValue:@"20.0" forKey:@"price"];
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if([keyPath isEqualToString:@"price"])
{
myLabel.text = [stockForKVO valueForKey:@"price"];
}
}
- (void)dealloc
{
[stockForKVO removeObserver:self forKeyPath:@"price"];
}