基于键值的观察者模式编程
键值观察提供了一个机制,允许当其他对象的特定属性被修改时通知观察者对象。这一机制在应用程序的模型和控制器之间的通讯方面尤其有用。通常情况下,控制器对象观察模型对象的属性,而视图对象通过控制器观察模型对象的属性。此外,一个模型对象也可以观察其他模型对象。
要接收一个属性的键值观察通知,需要:
- 被观察对象调用addObserver:forKeyPath:options:context:方法注册观察者对象;
- 观察类必须实现observeValueForKeyPath:ofObject:change:context:方法。
示例
1. 新建一个Single View Application,并启用ARC;
2. 新建一个StockData类,头文件如下所示:
@interface StockData : NSObject @property (assign, nonatomic) CGFloat price; @end
实现代码可以先不处理;
3. 在ViewController.m中,首先修改接口定义,代码如下:
#import "StockData.h" @interface ViewController () { StockData *_stock; UILabel *_label; } @end
4. 修改viewDidLoad方法如下:
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. // 1. 初始化StockData _stock = [[StockData alloc]init]; // 2. 新建标签控件显示StockData的price属性 _label = [[UILabel alloc]initWithFrame:CGRectMake(0, 100, 320, 40)]; [_label setTextAlignment:NSTextAlignmentCenter]; [self.view addSubview:_label]; // 3. 添加观察者观察price属性 [_stock addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionNew context:nil]; // 4. 测试属性变化 [_stock setPrice:20]; [_stock setPrice:30]; [_stock setPrice:40]; }
5. 实现observeValueForKeyPath:ofObject:change:context:方法,在viewDidLoad方法下方,添加如下代码:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqual:@"price"]) { NSLog(@"new price is %@", change[@"new"]); [_label setText:[NSString stringWithFormat:@"%0.02f", _stock.price]]; } }
6. 生成并运行程序,标签中应该显示40.00,不过在控制台可以看到3次price属性的变化情况。
补充
对于本此示例,由于是支持ARC的,因此没有删除观察者的代码。但是对于复杂些的应用,在不需要时,需要删除观察者监听。要做到这一点,可以调用如下代码:
[_stock removeObserver:self forKeyPath:@"price"];
搞定收工!