键值观察之KVO——即观察者模式的应用 补充与拓展

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







你可能感兴趣的:(键值观察之KVO——即观察者模式的应用 补充与拓展)