KVO简介:键值观察,是基于键值编码(KVC)的一种观察模式。 是iOS中常用的一种消息传递机制。
对接模式:发送者和接收者的关系为一对多的关系,一个发送者可以有多个接收者。
使用键值观察需要被观察对象编写符合KVC标准的存取方法,使用步骤分为以下三步:
- 第一步:注册成为KVO观察者
- 第二步:定义KVO的回调
- 第三步:移除KVO观察者
第一步:调用注册方法成为观察者
[ObjectOfObserved addObserver:observerObject forKeyPath:@"example" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
KVO注册方法参数:
- ObjectOfObserved:NSObject类型,为被观察者对象
- 参数Observer:NSObject类型,为观察者对象,即要注册成为观察者的对象(既然是在观察者的.m文件中实现的,那么该参数则为self)
- 参数KeyPath:NSString类型,键路径参数,描述将要观察的属性,即被观察者的属性参数。(如:被观察者有一个命名为example的属性,而且你要观察的正是这个属性,那就设置这个参数为@"example")
- 参数options:枚举类型,有四个选项,标识KVO希望变化如何传递给观察者,可以使用"|"进行多选(这里观察属性变化的新值和旧值)
options枚举:
1、NSKeyValueObservingOptionNew:该枚举值保证KVO监听属性的新内容,当属性内容变化时,KVO会记录属性的新内容,这样KVO回调方法中的参数change字典中包括改变后的值,可以通过KVO的监听回调方法获取到属性的新内容
2、NSKeyValueObservingOptionOld:该枚举值保证KVO监听属性的原内容,当属性内容变化时,KVO会记录属性的原内容,这样KVO回调方法中的参数change字典包括改变前的值,可以通过KVO的监听回调方法获取到属性的原内容
3、NSKeyValueObservingOptionInitial: 注册后立刻触发KVO通知,添加该枚举后,即使属性值没有变化,也会调用KVO回调方法
4、NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)
- 参数context:void类型指针,上下文内存区,通常设置为nil 。这个会传递到观察者的函数中,用来区分不同的监听消息。
如何设置context:
可以参考这篇文章Key-Value Observing中《正确的上下文声明》部分;以及这篇文章 kvo/gcd中关于context指针的赋值
第二步:在观察者的.m实现文件中定义KVO的回调方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
}
该方法是系统提供的观察者实现键值观察方法,作为观察者,需要实现这个方法。当被观察的被观察属性发生变化时(这里的变化是指赋值操作,只要给属性赋值就会调用,就算赋相同的内容,也会调用),会自动调用这个方法。
KVO回调方法中参数:
- 参数keyPath:NSString类型,被监听的keyPath , 用来区分不同的KVO监听
- 参数object:id类型,为被监察的对象
- 参数change:NSDictionary类型,保存被监察者信息的字典
- 参数context:void类型,上下文,用来区分不同的KVO监听
KVO回调方法操作:
- 当监听者监听了多个被监听者时,可以在回调方法中通过参数keyPath来判断是哪个监听消息,```
[keyPath isEqualToString:@"name"]
* 获取被监听者对象```
监听者对象类型 *变量名 = object;
- 获取被监听者内容未变时的属性对象```
属性对象类型 * old = [change objectForKey:NSKeyValueChangeOldKey];
* 获取被监听者内容已变时的属性对象```
属性对象类型 * new = [change objectForKey:NSKeyValueChangeNewKey];
第三步:在观察者的.m文件中的dealloc方法中移除观察者
- (void)dealloc {
// 调用移除观察者的方法:- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
[ObjectOfObserved removeObserver:Observer forKeyPath:@"example"];
}
KVO移除方法参数:
- ObjectOfObserved:NSObject类型,为被观察者对象
- 参数Observer:NSObject类型,为观察者对象,即要注册成为观察者的对象(既然是在观察者的.m文件中实现的,那么该参数则为self)
- 参数KeyPath:NSString类型,键路径参数,即被观察者的属性参数。(如:被观察者有一个命名为example的属性,而且你要观察的正是这个属性,那就设置这个参数为@"example")
注:如果忘记解除移除监察,会导致资源泄露
拓展一: KVO手动设置
KVO模型中,有两种通知观察者的方式,自动通知和手动通知。一般我们都用系统自动通知,文章开篇介绍的就是KVO自动通知。
KVO手动通知的设置出了完成自动通知的三个步骤,需要在被观察者的.m实现文件中重写类方法:
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key {
}
返回NO时,告诉系统使用KVO手动通知;返回YES时,使用KVO自动通知,默认为YES;
参数key为NSString类型,被监听的keyPath , 用来区分不同的KVO监听。
另外,在当被监听的属性发生变化时,需要调用属性值将要改变的方法和属性值已经改变方法
// 手动通知在需要改变example变量的地方,使用
[self willChangeValueForKey:@"example"];
self.example = @"我是被监听的属性,字符串类型的";
[self didChangeValueForKey:@"example"];
自动通知在需要改变example变量的地方,使用KVC设置属性内容的方法,而不是仅仅使用简单赋值。
[self setValue:@"我是被监听的属性,字符串类型的" forKey:@"example"];
手动改变属性内容时,我们需要在3个地方改变属性的内容值,即:请求结束时、连接出错误,线程被cancel。请在对应的方法代码中加入手动变值的语句。
拓展二: KVC简单介绍
可以参看这篇文章:iOS开发技巧系列---详解KVC(我告诉你KVC的一切)
参考文章
网友评论