iOS-观察者模式


iOS-观察者模式


何为观察者模式,也就是说当被观察者发生了改变要观察者知道,并作出相应的处理。本文先使用系统的,之后实现观察者模式来了解其真正原理。

目录:

1.系统观察者模式的使用

2.自定义观察者模式


下面我们来分解iOS编程中的观察模式的使用:

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

该方法是NSObject的一个扩展类目,通过它我们可以给对象添加观察者observer,观察者并不是关心被观察者的所用动态,它只是关心被观察者的一些特性的改变而已所以通过keyPath来指定,当keyPath改变了,你可以把它改变了什么东西通知给观察者,通过option来指定,还可以设置任意类型的上下文context。观察者所要做的内容是做出相应的改变。


-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context

这个也是NSOject的一个扩展类目,当被观察者的某个特性改变了,观察者如果对该特性观察了就会调用改函数


下面我们来使用系统提供的观察者模式:通过函数调用跟踪日志

#import <UIKit/UIKit.h>

@interface ViewController : UIViewController
@property (nonatomic,assign)int observeredAttr;
@end

@interface ViewController ()

@end

//函数调用跟踪静态变量
static int traceInt = 0;

@implementation ViewController{
    
}

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSLog(@"%d ------ %s",traceInt++,__func__);
    [self addObserver:self forKeyPath:@"observeredAttr" options:0 context:nil];
    //改变观察变量的值,这样它会出发观察者的操作
    [self changeObserverdAttr];
}

-(void)changeObserverdAttr{
    
    NSLog(@"%d ------ %s",traceInt++,__func__);
    self.observeredAttr = 100;
}
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    NSLog(@"%d ------ %s",traceInt++,__func__);

}

结果:

2015-04-02 21:03:06.366observer[928:30124] 0 ------ -[ViewController viewDidLoad]

2015-04-02 21:03:06.367observer [928:30124] 1 ------ -[ViewController changeObserverdAttr]

2015-04-02 21:03:06.367 observer[928:30124] 2 ------ -[ViewController observeValueForKeyPath:ofObject:change:context:]


重结果中可以看出来,添加观察者,这里设置为自己,改变被观察的属性,调用被观察的方法。


自定义观察者模式:

被观察者的设计:

头文件:

#import <Foundation/Foundation.h>

@interface ObserveredObject : NSObject
@property (nonatomic,assign)int observeredAttr;  //被观察的属性

//把观察者添加到列表中
-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
@end

实现文件:

#import "ObserveredObject.h"
#import "ObserverObject.h"

@implementation ObserveredObject
{
    //观察者队列字典
    NSMutableDictionary *_oberverQueue;
}
-(instancetype)init{
    if (self= [super init]) {
        _oberverQueue = [[NSMutableDictionary alloc]init];
    }
    return self;
}


//把观察者放到观察者字典中通过path来作为值,observer作为对象
-(void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath{
    NSLog(@"------ %s",__func__);
    [_oberverQueue setObject:observer forKey:keyPath];
}


//重写属性的set方法
-(void)setObserveredAttr:(int)observeredAttr{
     NSLog(@"------ %s",__func__);
    if (observeredAttr !=_observeredAttr) {
        NSArray *allKey = [_oberverQueue allKeys];
        for (int i= 0; i<allKey.count; i++) {
            if ([allKey[i] isEqualToString:@"observeredAttr"]) {
                ObserverObject *observer = [_oberverQueue objectForKey:@"observeredAttr"];
                [observer changedActionForPath:@"observeredAttr" andChangValue:[NSString stringWithFormat:@"%d",observeredAttr]];
            }
        }
    }
}
@end

观察者的设计:

头文件:

#import <Foundation/Foundation.h>

@interface ObserverObject : NSObject

//当观察的属性改变时掉用该方法
-(void)changedActionForPath:(NSString *)path andChangValue:(id)value;

@end

实现文件:

@implementation ObserverObject
-(void)changedActionForPath:(NSString *)path andChangValue:(id)value{
    
    NSLog(@"------ %s",__func__);

    if ([path isEqualToString:@"observeredAttr"]) {
        NSLog(@"你观察的对象的observeredAttr已经改变了%@",value);
    }
}
@end

自定义观察者模式的使用:

    NSLog(@"------ %s",__func__);
    //初始化被观察者
    ObserveredObject *ed = [[ObserveredObject alloc]init];
    //在没有添加观察者的时候初始化属性
    ed.observeredAttr = 50;
    //初始化观察者
    ObserverObject *ob = [[ObserverObject alloc]init];
    //为ed添加一个观察者,观察的属性为observeredAttr
    [ed addObserver:ob forKeyPath:@"observeredAttr"];
    
    //改变被观察者的属性的值
    ed.observeredAttr = 100;


运行结果:

2015-04-02 21:34:23.933 Target_action[1199:43513] ------ -[ViewController viewDidLoad]

2015-04-02 21:34:23.933 Target_action[1199:43513] ------ -[ObserveredObject setObserveredAttr:]

2015-04-02 21:34:23.933 Target_action[1199:43513] ------ -[ObserveredObject addObserver:forKeyPath:]

2015-04-02 21:34:23.933 Target_action[1199:43513] ------ -[ObserveredObject setObserveredAttr:]

2015-04-02 21:34:23.933 Target_action[1199:43513] ------ -[ObserverObject changedActionForPath:andChangValue:]

2015-04-02 21:34:23.933 Target_action[1199:43513] 你观察的对象的observeredAttr已经改变了100



小结:

使用系统自带的观察者模式要使用self.property的方法否则不会调用观察者的观察方法,系统的self.property的设计原理和上面自定义的setMethod原理差不多。谢谢。



郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。