iOS消息传递之KVO

  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 *)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的一切)

参考文章

  • Object-C — KVO & oc通知
  • KVO机制详解
  • 如何优雅地使用 KVO
  • Key-Value Observing

你可能感兴趣的:(iOS消息传递之KVO)