KVO观察者模式<代码演示>

来源:互联网 发布:2017年非农数据时间表 编辑:程序博客网 时间:2024/04/28 13:12
/*
     1.KVO
的键值观察是一种使用对象获取其他对象的特定属性变化的通知机制;
     2.
控制器层的绑定技术就是严格依赖键-值观察获得模型层和控制层的变化通知的;
     3.
对于不依赖控制器层类的应用程序,键-值观察者模式提供了一种简化的方法来
       
实现检查器并更新用户界面值;
     
     4.
Notification不同在于,键值观察中并没有所谓的中心对象来为所有观察者提供变化通知;
       
取而代之的是当有变化发生时,通知被直接发送到处于观察状态的对象,NSObject提供这种基
                 础键-值观察实现方法,我们几乎不用重载该方法;
     5.
我们可以观察到任意对象属性,包括简单属性,对一或是对多关系;
       A.
一对多关系的观察者将会被告知发生变化的类型,即任意发生变化
       B.
键值观察者模式为所有对象提供自动观察兼容性,因此可以通过禁止自动观察通知
         
并实现手动通知来筛选通知;
     */

    
/**************注册观察者模式*******************
     
     1.
为了正确接收属性的变化通知,观察者必须首先发送一个
       addObserver:forKeyPath:options:context:nil
消息至被观察对象;
       
用于传送观察对象和需要观察的属性的关键路径,以便于其注册;
     2.
选项参数指定了发送变更通知时提供给观察者的信息。
       A.
使用NSKeyValueObservingOptionOld可以原始初始化值以变更字典
         
的单项形式提供给观察者;
       B.
使用NSKeyValueObservingOptionNew选项,则可以将新的值以一个项
         
的形式添加至变更字典
       C.
可同时使用用按位与符号“|”即可,如:
         NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
        
     
代码示例:
     
         [self.patient addObserver:self//
执行监听的对象,在当前对象中注册的监听的方法
         forKeyPath:@"healthStatus"//
要监听的属性名称
         options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
         context:nil];
     
     *********************************************/

    
    
/**************接收观察者*******************
     
     1.
当监听的属性发生变化时,观察者收到
       observeValueForKeyPath:ofObject:change:context:
       
消息,观察者必须实现这一方法;
     2.
触发观察通知的对象和键路径,包含变更细节的字典,以及观察者注册时
       
提交的上下文指针均被提交给观察者;
     
     
-(void)observeValueForKeyPath:(NSString *)keyPath
                     ofObject:(id)object
                       change:(
NSDictionary *)change
                      context:(
void *)context{
    
            
if ([keyPath isEqual:@"key"]) {
                
NSLog(@"");
             }
    
         }
     
     *********************************************/

    
/**************移除观察者*******************
     
     
可以发送一条指定观察方对象和路径的removeObserver: forKeyPath:消息给被观察者
     
移除一个键值观察者(观察任务完成后)
     
     *********************************************/


/*
 
此类为被监听方-->Patient 病人
 */

@interface Patient : NSObject

//健康值
@property (nonatomic,assignNSInteger healthStatus;

@end
#import "Patient.h
//实现类
@implementation Patient

//重载init方法
-(
id)init{

    
if ((self = [super init])) {
        
self.healthStatus = 100;//设置初始健康值
        
//设置一个定时器,每隔2秒发送变化的健康值
        [
NSTimer scheduledTimerWithTimeInterval:2
                                         
target:self
                                       
selector:@selector(healthStatusChange)
                                       
userInfo:nil
                                        
repeats:YES];
    }
    
return self;
}
//实现定时器方法
-(
void)healthStatusChange{

    
self.healthStatus--;//健康值

}

@end

#import "Patient.h"
/*
 
此处为演示监听者模式:的监听方——>Doctor医生lei
 */

//@class Patient;//告诉该类有Patient存在

@interface Doctor : NSObject

@property (nonatomic,retainPatient *patient;
//定义一个初始化方法
-(
id)initWithPatient:(Patient *)patient;
@end

#import "Doctor.h"
//#import "Patient.h"
@implementation Doctor

-(
id)initWithPatient:(Patient *)patient{

    
if ((self = [super init])) {
        
self.patient = patient;
//        _patient = [patient retain];
        [
self.patient addObserver:self//执行监听的对象,在当前对象中注册的监听的方法
                       
forKeyPath:@"healthStatus"//要监听的属性名称
                          
options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld
                          
context:nil];
    }

    
return self;
}
//实现监听会触发的方法
-(
void)observeValueForKeyPath:(NSString *)keyPath//监听属性路径
                     ofObject:(
id)object//执行监听的对象
                       change:(
NSDictionary *)change//监听的旧值或新值
                      context:(
void *)context{//监听方法中传过来的
    
    
NSLog(@"%@",change);
    
}
-(
void)dealloc{
    
RELEASE_SAFETY(_patient);
    [
_patient removeObserver:self forKeyPath:@"healthStatus"];
    [
super dealloc];
}

@end

//开始监听    
    //实例化一个Patient
    
Patient *patient = [[Patient allocinit];
    
//实例化 Doctor
    
Doctor *doctor = [[Doctor allocinitWithPatient:patient];
    
//开启定时器
    [[
NSRunLoop currentRunLooprun];



0 0