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>
运行结果如下: