addObserver 方法与observeValueForKeyPath方法配套使用
<1> - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;
此方法用于为对象的某个属性添加观察者,当对象被观察的属性值发生变化时就会触发observeValueForKeyPath
并把options和context值传过去
注意:
observer:表示被监听的对象属性值发生变化时触发的observeValueForKeyPath方法的所在对象
forKeyPath: 表示监听对象(为其添加观察者的对象)的具体成员属性变量名
options: 表示当所监听对象的属性值发生变化时把哪些值传给observeValueForKeyPath方法
context: 可以为任意类型的数据,表示额外发送一些任意关于此监听对象信息
<2> - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;
keyPath: 与被监听对象的具体某个属性名相同。用来判断被监听对象的哪个成员值发生了变化
change: 是一个字典类型,存储的是addObserver方法发送的option值
contex:接受addObserver方法发送的context值
<3> - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
当不再需要观察者观察对象的属性值时,应该让被观察的对象移除观察者
具体详情 请看代码:
新建工程
新建Child类 变价Child.h如下:
<span style="font-size:18px;">// // Child.h // KVO键值观察补充 // // Created by apple on 15/9/21. // Copyright (c) 2015年 LiuXun. All rights reserved. // #import <Foundation/Foundation.h> @interface Child : NSObject { NSInteger happyVal; NSInteger hungryVal; } @property (nonatomic, assign) NSInteger happyVal; @property (nonatomic, assign) NSInteger hungryVal; @end </span>编辑Child.m如下:
<span style="font-size:18px;">// // Child.m // KVO键值观察补充 // // Created by apple on 15/9/21. // Copyright (c) 2015年 LiuXun. All rights reserved. // #import "Child.h" @implementation Child @synthesize happyVal, hungryVal; -(id)init { if (self = [super init]) { self.happyVal = 100; self.hungryVal = 100; [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES]; } return self; } -(void)timerAction:(NSTimer *) timer { self.happyVal--; // 注意这里要使用点语法即调用变量的set方法才能触发观察者监听 //self.hungryVal--; NSNumber *hun = [NSNumber numberWithInteger:--hungryVal]; [self setValue:hun forKey:@"hungryVal"]; //注意KVC也可以被观察者监听到 // 切记:直接使用变量进行增加或其他变化 如happVal++ 之类的是不可以被观察者监听到的,只有KVC或使用点语法即调用被监听变量的set方法才可以被观察者监听到 } @end </span>新建护士类,编辑Nurse.h如下:
<span style="font-size:18px;">// // Nurse.h // KVO键值观察补充 // // Created by apple on 15/9/21. // Copyright (c) 2015年 LiuXun. All rights reserved. // #import <Foundation/Foundation.h> #import "Child.h" @interface Nurse : NSObject { Child *child; } @property (nonatomic, strong) Child *child; -(id) initWithChild:(Child *) _child; @end </span>编辑Nurse.m如下:
<span style="font-size:18px;">// // Nurse.m // KVO键值观察补充 // // Created by apple on 15/9/21. // Copyright (c) 2015年 LiuXun. All rights reserved. // #import "Nurse.h" @implementation Nurse @synthesize child; -(id)initWithChild:(Child *)_child { if (self = [super init]) { child = [_child retain]; // 使用KVO为child添加一个观察者 用于监听happyVal是否被修改了 [child addObserver:self forKeyPath:@"happyVal" options:NSKeyValueObservingOptionNew| NSKeyValueObservingOptionOld context:@"监听孩子的欢乐值"]; // 使用KVO为child再添加一个观察者 用于监听hungryVal是否被修改了 [child addObserver:self forKeyPath:@"hungryVal" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"监听孩子的饥饿值"]; /* 注意: observer: 表示被监听的对象属性值发生变化时触发的observeValueForKeyPath方法的所在对象 forKeyPath: 表示监听对象(为其添加观察者的对象)的具体成员属性变量名 options: 表示当所监听对象的属性值发生变化时把哪些值传给observeValueForKeyPath方法 context: 可以为任意类型的数据,表示额外发送一些任意关于此监听对象信息 */ } return self; } //一旦监听的child对象的happyVal值或hungryVal发生变化时,就会触发以下方法 // 与上面的addObserver方法是配套使用的 -(void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { if ([keyPath isEqualToString:@"happyVal"]) { // 被监听child对象的happyVal发生变化 NSNumber *happy = [change objectForKey:@"new"]; NSInteger value = [happy integerValue]; NSLog(@"context = %@",context); NSLog(@"change= %@",change); NSLog(@"快乐值是:%0.1f%%", value/100.0*100); if (value< 98 ) { // 假设欢乐值小于80 孩子会哭 需要护士去哄 [self playWithChild]; [child setValue:@100 forKey:@"happyVal"]; } } else if ([keyPath isEqualToString:@"hungryVal"]) { // 被监听child对象的hungryVal发生变化 NSNumber *hungry = [change objectForKey:@"new"]; NSInteger value = hungry.integerValue; NSLog(@"context = %@",context); NSLog(@"change = %@",change); NSLog(@"饥饿值是:%0.1f",value/100.0*100); if (value <95) { // 饥饿值小于70 需要保姆去喂 [self feedChild]; [child setValue:@100 forKey:@"hungryVal"]; } } /* 注意: keyPath: 与被监听对象的具体某个属性名相同。用来判断被监听对象的哪个成员值发生了变化 change: 是一个字典类型,存储的是addObserver方法发送的option值 contex: 接受addObserver方法发送的context值 */ } -(void)playWithChild { NSLog(@"护士陪小孩玩"); } -(void) feedChild { NSLog(@"保姆给小孩喂奶"); } -(void)dealloc { [child removeObserver:self forKeyPath:@"happyVal" ]; [child removeObserver:self forKeyPath:@"hungryVal"]; [child release]; [super dealloc]; } @end</span>在main.m中编辑代码如下:
<span style="font-size:18px;">// // main.m // KVO键值观察补充 // // Created by apple on 15/9/21. // Copyright (c) 2015年 LiuXun. All rights reserved. // #import <Foundation/Foundation.h> #import "Child.h" #import "Nurse.h" int main(int argc, const char * argv[]) { @autoreleasepool { Child *child = [[Child alloc] init]; Nurse *nurse = [[Nurse alloc] initWithChild:child]; // NSDate *current = [NSDate date]; // NSTimeInterval *inter = [[current timeIntervalSince1970] +10 ]; // NSDate *until = [NSDate dateWithTimeIntervalSince1970:inter]; NSDate *until = [NSDate dateWithTimeIntervalSinceNow:10]; [[NSRunLoop currentRunLoop] runUntilDate:until]; [child release]; [nurse release]; } return 0; } </span>运行结果如下: