您的位置:首页 > 其它

键值观察之KVO——即观察者模式的应用

2015-09-20 23:43 274 查看
KVO的基本概念

1、基本概念:

Key Value Observing ,直译为:基于键值的观察者。它提供一种机制,当指定的对象的属性被修改后,则对象就会接收到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。(常用于监听进度条的值)

与NSNotification不同,键-值 观察中并没有所谓的中心对象来为观察者提供变化通知。取而代之的,当有变化时,通知被直接发送至处于观察状态的对象。NSObject提供这种基础的 键-值 观察实现方法。

我们可以观察任意对象属性,包括简单属性,一对一或一对多关系。对多关系的观察者将会被被告知发生变化的类型-也就是任意发生变化的对象。

键-值 观察为所有对象提供自动观察兼容性。我们可以通过禁用自动观察通知并实现手动通知来筛选通知。

2、代理与观察者的区别就是:代理是一对一,观察者是一对多的。

就是说一个对象的代理只能是一个,就好比一次只能给一个人打电话一样,而观察者就好比是广播,所有人都会受到通知。代理只能实现一对一是无法实现一对多的。

新建工程:

创建一个孩子类:

编辑Child.h如下:

//
//  Child.h
//  KVOTest
//
//  Created by yanlu guo on 13-7-28.
//  Copyright (c) 2013年 河北科技大学. All rights reserved.
//

#import <Foundation/Foundation.h>

@interface Child : NSObject
{
NSInteger happyVal;
}

@property(nonatomic,assign) NSInteger happyVal;

@end
编辑Child.m如下:

//
//  Child.m
//  KVOTest
//
//  Created by yanlu guo on 13-7-28.
//  Copyright (c) 2013年 河北科技大学. All rights reserved.
//

#import "Child.h"

@implementation Child

@synthesize happyVal;

// 可以发现孩子类中并没有护士的对象  但是护士仍然受到了通知
// 并不只是护士 ,而是所有的类的中都可以为孩子添加一个观察者
-(id)init{
if(self = [super init]){
self.happyVal = 100;
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
}
return self;

}

-(void) timerAction:(NSTimer *) timer{
self.happyVal--;  // 注意:使用点语法即 调用set方法才能触发监听操作
}

@end
新建护士类 当孩子快乐值减到一定程度时 观察者就会通知护士执行照顾孩子的操作

编辑Nurse.h如下:

//
//  Nurse.h
//  KVOTest
//
//  Created by yanlu guo on 13-7-28.
//  Copyright (c) 2013年 河北科技大学. All rights reserved.
//

#import <Foundation/Foundation.h>
#import "Child.h"

@interface Nurse : NSObject
{
Child * child;
}

@property(nonatomic,retain) Child * child;

-(id) initWithChild:(Child *) _child;
@end
编辑Nurse.m如下:

//
//  Nurse.m
//  KVOTest
//
//  Created by yanlu guo on 13-7-28.
//  Copyright (c) 2013年 河北科技大学. All rights reserved.
//

#import "Nurse.h"

@implementation Nurse
@synthesize child;

-(id) initWithChild:(Child *) _child{
if(self = [super init]){
child = [_child retain];
// 使用KVO 为child添加一个观察者  用于监听happyVal是否被修改了

// 把新旧值都传过来  self表示在当前类中执行监听方法
// | 表示把新的值和旧的值(即监听的happyVal的新值和旧值都传过来)
[child addObserver:self forKeyPath:@"happyVal" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:@"xxx"];
}
return self;
}

-(void) dealloc{
[child removeObserver:self forKeyPath:@"happyVal"];
[child release];
[super dealloc];
}

// 一旦监听的happyVal的值被修改就会触发下面的方法
// 以下方法是NSObject的方法 触发监听后执行  与前面的  addObserver方法是配套使用的
-(void) observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context{
NSNumber *happyValue = [change objectForKey:@"new"];
NSInteger value = happyValue.integerValue;
NSLog(@"快乐值是:%0.1f %%",value/100.0* 100);
if (value< 80) {   // 如果小孩的欢乐值小于80  就会哭
[self play];   // 观察者就会通知保姆照顾小孩
[child setHappyVal:100];  // 孩子的欢乐值又重新变为100
}

}

-(void)play
{
NSLog(@"陪小孩玩");
}

@end


在main.m中编辑如下:
//
//  main.m
//  KVOTest
//
//  Created by yanlu guo on 13-7-28.
//  Copyright (c) 2013年 河北科技大学. 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 alloc] initWithChild:child];
[[NSRunLoop currentRunLoop] run];

}
return 0;
}


运行结果如下:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: