KVO即键值观察者,它提供了一个观察者模式,用于监听某个对象属性值的变化,可以实现一个观察者,一个被观察者,多个接收者之间的通信关系。
KVO的工作流程:
1.被观察者属性发生变化(child对象的cleanValue发生变化)
2.观察者监听到属性的变化(KVO帮我们实现了观察者的业务逻辑)
3.观察者会调用观察者方法通知到事件的接收者(观察者通知到保姆)
4.事件接收者响应这个事件。
在接收者类中添加小孩的观察者,对象写self,下面实现观察者方法,其中改变小孩的相关属性值,最后手动移除观察者
相关方法:
1、添加观察者的方法:
_child:被观察者
addObserver:事件的接收者
options:表示在观察者方法的change参数中能够获取的值。
context:传递的参数
[_childaddObserver:selfforKeyPath:@"cleanValue"options:NSKeyValueObservingOptionNewcontext:NULL];
2、观察者响应事件的方法:
//keyPath:被观察者监听的属性名
//object:被观察者
//change:是一个字典,提供了关于KVO的有效信息,比如key:new时表示的是属性变化后的新值,key:old表示的是属性变化前的旧值
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {}
举例:小孩脏了,需要保姆来打理
给小孩添加一个观察者,事件的接收者是保姆,观察者把小孩洁净度这个属性值传递到保姆,保姆去响应打理小孩的方法。
#import "Child.h"
@implementation Child
- (instancetype)init {
if (self = [super init]) {
_cleanValue = 100;
_happyValue = 100;
}
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(timerAction:) userInfo:nil repeats:YES];
return self;
}
- (void)timerAction:(NSTimer *)timer {
//1.只有通过两种方式进行属性值的设置才能被KVO所监听到
// (1)用setter方法
// (2)KVC
//这种方法不能被KVO监听到
// _cleanValue--;
// _happyValue--;
self.cleanValue = _cleanValue - 1;
self.happyValue = _happyValue - 1;
NSLog(@"cleanValue:%li,happyValue:%li", _cleanValue, _happyValue);
}
@end
#import "Nanny.h"
#import "Child.h"
@implementation Nanny
- (instancetype)initWithChild:(Child *)child {
if (self = [super init]) {
_child = child;
//使用KVO来监听小孩属性值的变化,需要给小孩添加一个观察者,必须在注册观察者以后才能够监听到小孩属性值的变化。
/*
给被观察者注册一个观察者,来监听被观察者属性的变化。
_child:被观察者
addObserver:事件的接收者
options:表示在观察者方法的change参数中能够获取的值。
context:传递的参数
*/
[_child addObserver:self forKeyPath:@"cleanValue" options:NSKeyValueObservingOptionNew context:NULL];
[_child addObserver:self forKeyPath:@"happyValue" options:NSKeyValueObservingOptionNew context:NULL];
}
return self;
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
//keyPath:被观察者监听的属性名
//object:被观察者
//change:是一个字典,提供了关于KVO的有效信息,比如key:new时表示的是属性变化后的新值,key:old表示的是属性变化前的旧值
NSLog(@"%@", change);
if ([keyPath isEqualToString:@"cleanValue"]) {
NSNumber *newValue = change[@"new"];
if ([newValue integerValue] < 95) {
//保姆针对小孩脏了事件的处理代码
NSLog(@"保姆给小孩洗白白");
_child.cleanValue = 100;
}
}
else if ([keyPath isEqualToString:@"happyValue"]) {
NSNumber *newValue = change[@"new"];
if ([newValue integerValue] < 90) {
//保姆针对小孩脏了事件的处理代码
NSLog(@"保姆逗小孩开心");
_child.happyValue = 100;
}
}
//用KVO也实现了小孩和保姆之间的通信,小孩可以脱离保姆而存在,进行解耦合,如果想换一个照顾小孩的类,只要在类中添加观察者,并且实现观察者方法就可以。
}
- (void)dealloc {
//在保姆对象被释放之前,要移除观察者。ARC无法帮我们完成。
[_child removeObserver:self forKeyPath:@"cleanValue"];
[_child removeObserver:self forKeyPath:@"happtValue"];
}
@end