键值观察(KVO)是基于键值编码的一种技术。
利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知。
被观察对象需要编写符合KVC标准的存取方法,编写键值观察分为以下三步:
(1)注册成为观察者。
(2)定义KVO的回调。
(3)移除观察者。
+新建一个类Student,属性为name,age。
@interface Student : NSObject @property(copy,nonatomic) NSString * name; @property(nonatomic) int age; @end
新建一个Parent类,作为观察者。main函数:
Student * student = [Student new];
Parent * parent = [Parent new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
第一个参数:(student)被观察者。
第二个参数:(parent)观察者。
第三个参数:(forKeyPath)键路径参数,要观察的键路径,这里观察name和age。
第四个参数:(options)标识KVO希望变化如何传递给观察者,可以使用|进行多选,这里观察变化的新值和旧值。
第五个参数:上下文内存区,通常为nil
+在parent.m的文件中定义KVO的回调。
@implementation Parent
//观察者实现键值观察方法,要作为观察者,需要实现这个方法。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"家长观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
}
其中change是一个字典。
+如果student的name或age发生变化(最后要移除观察者):
Student * student = [Student new];
Parent * parent = [Parent new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
student.age = 10;
student.name = @"小明";
//结束之前需要移除观察者
[student removeObserver:parent forKeyPath:@"age"];
[student removeObserver:parent forKeyPath:@"name"];
那么parent上定义的的回调会自动执行,打印结果:

当然也可以多个对象观察一个对象,新建teacher类,这样就有两个观察者:
Student * student = [Student new];
Parent * parent = [Parent new];
Teacher * teacher = [Teacher new];
//建立观察者模式关系,注册观察者
[student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
[student addObserver:teacher forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
[student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
context:nil];
student.age = 10;
student.name = @"小明";
//结束之前需要移除观察者
[student removeObserver:parent forKeyPath:@"age"];
[student removeObserver:parent forKeyPath:@"name"];
[student removeObserver:teacher forKeyPath:@"age"];
****************************************
另外一种情况:新建Family类,让student成为它的一个属性,然后让Family成为student的观察者,这样注册观察者的方法可以写在Family的init方法中,移除观察者写在Family的dealloc方法中:
Family.h文件:
@interface Family : NSObject @property(strong,nonatomic) Student * student; -(id) initWithStudent:(Student *)student; @end
Family.m文件:
@implementation Family
-(id)initWithStudent:(Student *)student
{
if(self = [super init]){
self->_student = student;
//让当前对象成为student的观察者
[self->_student addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld context:nil];
}
return self;
}
//观察者实现键值观察方法,要作为观察者,需要实现这个方法。
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
id newValue = [change objectForKey:NSKeyValueChangeNewKey];
NSLog(@"家庭观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
}
-(void)dealloc
{
NSLog(@"Family dealloc...");
//移除观察者
[self->_student removeObserver:self forKeyPath:@"name"]; //ARC所以不用写super dealloc
}
@end
main:
Student * student = [Student new];
Family * family = [[Family alloc]initWithStudent:student];
student.name = @"hehe";
原文:http://www.cnblogs.com/liuyingjie/p/4949100.html