KVO (Key Value Observing)是ios里面一种特别方便的机制用于“捕捉”对象属性的变化。在概念理解上,是设计模式里面观察者模式的一种实践。
拿一个具体的例子来讲:
有一个数据对象EmployeeData,该对象有一个属性salary
有一个ViewController 用于显示对象EmployeeData的属性salary的值
当salary的值发生变化的时候,ViewController如何显示变化后的新值。
方案一:
“可以在EmployeeData类弱引用ViewController类,然后在EmployeeData数据发生变化时,调
用ViewController类的回调函数。这个方法虽然能达到目的,但是会破坏EmployeeData的完整
性,一个负责数据管理的类,不应当依赖另一个负责视图控制的类;换句话说,EmployeeData
类不应该知道关于ViewController类的任何事情,甚至不需要知道其从在”
方案二:
使用ios提供的消息中心(NSNotificationCenter)。在此EmployeeData为消息生产者,ViewController为消息消费者。当salary数据发生变化时发送一个消息既可。
ViewController接收到salary数据变化的通知做相对应的业务处理。不足之处如同方案一,EmployeeData对象的salary每次变动都需要发送“通知”。这项工作对EmployeeData自身来讲毫无意义。
方案三:
在ViewController中将自身(self)设置为EmployeeData salary属性值变化的观察者。当salary值发生变化时,执行一个回调方法。这样对“EmployeeData”来讲不用关心除自身业务以
外的事情。避免了方案一和方案二的瑕疵。对ViewController来讲关注谁的变化,注册自己为其的观察者既可。间接轻便。
下面是一些核心的代码。
// // EmployeeData.h // KVOExample // // Created by gaoyong on 12-8-8. // Copyright (c) 2012年 gaoyong. All rights reserved. // #import <Foundation/Foundation.h> @interface EmployeeData : NSObject { NSString *salary; } @property(nonatomic,retain) NSString *salary; @end // // EmployeeData.m // KVOExample // // Created by gaoyong on 12-8-8. // Copyright (c) 2012年 gaoyong. All rights reserved. // #import "EmployeeData.h" @implementation EmployeeData @synthesize salary; @end // // ViewController.h // KVOExample // // Created by gaoyong on 12-8-8. // Copyright (c) 2012年 gaoyong. All rights reserved. // #import <UIKit/UIKit.h> @interface ViewController : UIViewController { UILabel *salary; } @property(nonatomic,retain) IBOutlet UILabel *salary; @end // // ViewController.m // KVOExample // // Created by gaoyong on 12-8-8. // Copyright (c) 2012年 gaoyong. All rights reserved. // #import "ViewController.h" #import "EmployeeData.h" @interface ViewController () { EmployeeData *employeeData; } @end @implementation ViewController @synthesize salary; - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. employeeData = [[EmployeeData alloc] init]; [employeeData addObserver:self forKeyPath:@"salary" options:NSKeyValueObservingOptionNew context:nil]; } -(void)viewDidAppear:(BOOL)animated { //employeeData.salary = @"20"; //salary.text = employeeData.salary; employeeData.salary = @"20"; employeeData.salary = @"200"; employeeData.salary = @"2000"; employeeData.salary = @"20000"; employeeData.salary = @"200000"; } - (void)viewDidUnload { [super viewDidUnload]; // Release any retained subviews of the main view. } - (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation { return (interfaceOrientation != UIInterfaceOrientationPortraitUpsideDown); } -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { NSLog(@"observeValueForKeyPath is run"); // 美妙在这里:这一行会打印5次。 if (object == employeeData && [keyPath isEqualToString:@"salary"]) { self.salary.text = employeeData.salary; } } -(void) dealloc { [employeeData removeObserver:self forKeyPath:@"salary"]; } @end