美文网首页
iOS消息传递之KVO

iOS消息传递之KVO

作者: 西叶lv | 来源:发表于2017-05-06 22:49 被阅读102次

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

    参考文章

    相关文章

      网友评论

          本文标题:iOS消息传递之KVO

          本文链接:https://www.haomeiwen.com/subject/jwyetxtx.html