iOS-KVO详解
(观察者模式:注册监听、事件回调)
Key-Value-Observing ,一个对象能够观察另外一个对象的属性的值。当指定对象的属性被修改后,则对象就会接受到通知。(简单来说就是每次指定被观察的对象的属性被修改后,KVO就会自动通知响应的观察者了)
在OC中要实现KVO则必须实现NSKeyValueObserving协议,不过幸运的是NSObjkect已经实现了该协议。因此几乎所有的对象都可以使用KVO。
KVO使用:
①被观察者发出:-(void)addObserver:(NSObject*)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void*)context;
②然后只要被观察者的keyPath值发生变化(单纯改变其值不会调用此方法,只有通过getters和setters来改变值才会触发KVO),就会在观察者里调用方法:
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context; 来对KVO发出的通知做出响应。
③(这些代码都只需要在观察者里进行实现,被观察者不用添加任何代码,所以谁要监听谁注册,然后对响应进行处理即可,运用灵活简单;但是KVO只能检测类中的属性,并且属性名都是通过NSString来查找,编译器不会帮你检错和补全,纯手敲所以比较容易出错、当释放观察者时不需要移除观察者)
KVO实例(使用场景)
1.KVO观察属性变化
//1注册创建观察者 //2有一个回调函数,对被观察者的变化,可以进行相应的处理 //3移除或销毁创建的观察者 People * people = [[People alloc] init]; [people registerObservater]; [[NSRunLoop currentRunLoop] run];
@implementation People - (instancetype)init { self = [super init]; if (self) { _bank = [[Bank alloc] init]; } return self; } //创建一个标识符 static void * bankBalance = (void *)&bankBalance; - (void)registerObservater{ //创建观察者 [_bank addObserver:self forKeyPath:@"money" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:bankBalance]; } //创建一个回调函数 - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{ NSLog(@"%@---%@--%@----",keyPath,object,change); // if ([keyPath isEqualToString:@"money"]) { // // } //假设有多个观察者,以此来判断,不建议用上面的那个 if (context==bankBalance) { } } //销毁观察者 - (void)dealloc{ [self removeObserver:self forKeyPath:@"money"]; [super dealloc]; } @end
2.KVO传值
@property NSString *sendValue; //存放点击某一行的值 detail=[[DetailViewController alloc] init]; //添加观察者 [self addObserver:detail forKeyPath:@"sendValue" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil]; //Cell跳转赋值操作 self.sendValue=[NSString stringWithFormat:@"%ld",indexPath.row+1];
//接收并显示 //重写通知中心函数 -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{ NSString *strValue=change[@"new"]; label.text=strValue; }
3.一键换肤
@implementation ChangeBGTool + (instancetype)changeAllBackgroungColor { static ChangeBGTool * __bgColor = nil; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ __bgColor = [[self alloc] init]; }); return __bgColor; } - (instancetype)init { self = [super init]; if (self) { self.color = [UIColor whiteColor]; } return self; } @end
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. ChangeBGTool * single = [ChangeBGTool changeAllBackgroungColor]; [single addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew context:nil]; self.view.backgroundColor = [single valueForKeyPath:@"color"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { UIColor * color = (UIColor *)change[@"new"]; self.view.backgroundColor = color; }
//二级界面
- (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view from its nib. ChangeBGTool * single = [ChangeBGTool changeAllBackgroungColor]; [single addObserver:self forKeyPath:@"color" options:NSKeyValueObservingOptionNew context:nil]; self.view.backgroundColor = [single valueForKeyPath:@"color"]; } - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { UIColor * color = (UIColor *)change[@"new"]; self.view.backgroundColor = color; } - (void)dealloc { //移除观察者 [[ChangeBGTool changeAllBackgroungColor] removeObserver:self forKeyPath:@"color" context:nil]; }