iOS 中监听某个值的改变有哪些方法?
在一个复杂的,有状态的系统中,当一个对象的状态发生改变,如何通知系统,并对状态改变做出相应的行为是必需考虑的一个问题,在iOS中为这类问题提供了4种解决方法:
1. NSNotifiactaion 和 NSNotificationCenter:通知中心 2. Delegates:代理, 3. Callback:回调, 4. KVO(Key-Value Observing):键值观察
Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
|
KVO 是什么?
Objective-C 中的键(key)-值(value)观察(KVO)并不是什么新鲜事物,它来源于设计模式中的观察者模式,其基本思想就是:
一个目标对象管理所有依赖于它的观察者对象,并在它自身的状态改变时主动通知观察者对象。这个主动通知通常是通过调用各观察者对象所提供的接口方法来实现的。观察者模式较完美地将目标对象与观察者对象解耦。
|
KVO 的用法
1. 如果要监听“对象A”属性值的改变,先要为"对象A"的属性注册观察者(假设观察者为“对象B”)。
- (void)addObserver:(NSObject * _Nonnull)
anObserver forKeyPath:(NSString * _Nonnull)keyPath options:(NSKeyValueObservingOptions)options context:(void * _Nullable)
context
options 解释如下:
// NSKeyValueObservingOptionNew : change 字典中包含 key 改变后的新值
// NSKeyValueObservingOptionOld : change 字典中包含 key 改变前的旧值 // NSKeyValueObservingOptionInitial : 在添加观察者的时候立即发送一个通知给观察者,并且是在注册观察者方法返回之前 // NSKeyValueObservingOptionPrior : 如果指定,则在每次修改属性时,会在修改通知被发送之前预先发送一条通知给观察者,这与-willChangeValueForKey:被触发的时间是相对应的。这样,在每次修改属性时,实际上是会发送两条通知。
2. 观察者“对象B”实现
observeValueForKeyPath:ofObject:change:context: . 方法
3. “对象A”移除监听者 - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
|
例子:
//
// ViewController.m
// KVO test // // Created by KeSen on 15/9/1. // Copyright (c) 2015年 KeSen. All rights reserved. // #import "ViewController.h" #import "KSBaby.h" @interface ViewController () { KSBaby *_baby; } @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. KSBaby *baby = [[KSBaby alloc] initWithHungry:@"cryed" thirst:NO]; _baby = baby;
// 一般如下使用
// [_baby addObserver:self forKeyPath:@"cry" options: 0 context: nil];
[_baby addObserver:self forKeyPath:@"cry" options: NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld| NSKeyValueObservingOptionInitial | NSKeyValueObservingOptionPrior context:@"ssss"]; } - (void)dealloc { [_baby removeObserver:self forKeyPath:@"cry"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"keyPath: %@ change: %@ context: %@ ", keyPath, change, context); } - (IBAction)click:(UIButton *)sender { _baby.cry = @"crying"; } @end
|
那么:程序启动时输出:
点击按钮后输出:
|