KVO的基本概念
1、基本概念:
Key Value Observing ,直译为:基于键值的观察者。它提供一种机制,当指定的对象的属性被修改后,则对象就会接收到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。(常用于监听进度条的值)
与NSNotification不同,键-值 观察中并没有所谓的中心对象来为观察者提供变化通知。取而代之的,当有变化时,通知被直接发送至处于观察状态的对象。NSObject提供这种基础的 键-值 观察实现方法。
我们可以观察任意对象属性,包括简单属性,一对一或一对多关系。对多关系的观察者将会被被告知发生变化的类型-也就是任意发生变化的对象。
键-值 观察为所有对象提供自动观察兼容性。我们可以通过禁用自动观察通知并实现手动通知来筛选通知。
2、代理与观察者的区别就是:代理是一对一,观察者是一对多的。
运行结果如下:
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
// 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;
}
运行结果如下: