iOS原生观察者模式&重新设计观察者模式
原生KVO的实现依赖于强大的runtime运行时机制,实现原理大致为:当观察某对象A的属性时,会动态的创建这个类的子类,并为这个新的子类重写了Setter方法,在这个Setter方法里面负责通知观察者属性变化的情况。
前段时间面试的时候,面试官问我,如果不用系统的KVO模式,自己来实现一种设计模式,当时可能由于紧张,一下子没反应过来,最后结果可想而知,现在想来,对比现在所在的外包公司的种种不公平待遇,总结下来一句话,肚子里没货还真不行。
闲话不多扯,先来简单说一下如何自己实现NSNotificationCenter通知模式,然后,细聊如何通过协议实现KVO,不同于原生KVO的实现方案。
通知中心实现方案,首先进行角色划分,一个单例类A+抽象协议接口(包含接收到通知后实现的接口和发出通知的接口)Protocol+具体的实现类B;
客户端: A 包含属性数组 ,B遵循Protocol,实现协议方法,A数组持有B对象,当A发出通知时,取出数组中的B对象,通过运行时,让B实现协议方法,从而达到通知的目的。
这里,我们重点看一下KVO的实现方案,首先进行角色划分:
第一步 : 抽象出接口:所有观察者必须遵循这个协议
// 抽象观察者Observer
@protocol Observer
- (void)update:(Observable *)o msg:(NSObject *)msg;
@end
第二步:定义一个基类Observable,所有被观察者对象都必须继承于Observable基类
// 注册观察者- (void)addObserver:(id)o;
// 删除观察者- (void)deleteObserver:(id)o;// 删除所有观察者
- (void)deleteObservers;// 观察者数量
- (NSInteger)countObserver;// 通知
- (void)notifyObservers;- (void)notifyObservers:(NSObject *)msg;
// 更新数据
- (void)setChanged;// 取消更新
- (void)clearChanged;// 获取更新状态
- (BOOL)hasChanged;
Observable.m文件实现:
#import "Observable.h"@interface Observable()
@property (nonatomic,strong) NSMutableArray *obsArray;
@property (nonatomic,assign) BOOL changed;
@end
// 被观察者
@implementation Observable
- (instancetype)init{
if (self = [super init]) {
_obsArray = [NSMutableArray array];
_changed = NO; }
return self;}
// 注册观察者
- (void)addObserver:(id)o { [_obsArray addObject:o];}
// 删除观察者
- (void)deleteObserver:(id)o { [_obsArray removeObject:o];}
// 删除所有观察者
- (void)deleteObservers { [_obsArray removeAllObjects];}
// 观察者数量
- (NSInteger)countObserver { return _obsArray.count;}
- (void)notifyObservers { [self notifyObservers:nil];}
- (void)notifyObservers:(NSObject *)msg
{
if (!_changed) { return ; }
[self clearChanged];
for (idobj in _obsArray) {
[obj update:self msg:msg];
}
}
// 更新数据
- (void)setChanged {
_changed = YES;
}
// 取消更新
- (void)clearChanged {
_changed = NO;
}
// 获取更新状态
- (BOOL)hasChanged {
return _changed;
}
客户端实现:
WXObservable *observable = [WXObservable new];
[observable addObserver:[CoffeeObserver new]];
[observable addObserver:[SimpleObserver new]];
[observable setTitle:@"思维的切换"];
[observable push];
[observable push];
[observable push];