IOS开发入门iOS键值观察KVO实例详解
白羽 2019-05-21 来源 :网络 阅读 499 评论 0

摘要:本文将带你了解IOS开发入门iOS键值观察KVO实例详解,希望本文对大家学IOS有所帮助。

    本文将带你了解IOS开发入门iOS键值观察KVO实例详解,希望本文对大家学IOS有所帮助。


IOS开发入门iOS键值观察KVO实例详解


简介
   什么是KVO?KVO是Key-Value  Observing的简称,翻译成中文就是键值观察。这是iOS支持的一种机制,用来做什么呢?我们在开发应用时经常需要进行通信,比如一个model的某个数据变化了,界面上要进行相应的变化,但是如果我们程序并不知道数据什么时候会进行变化,总不能一直循环判断有没有变化吧,那么就需要在数据变化时给controlller发送一个通知,告知我变化了,你可以更新显示内容了,通知的方式有很多种,比如Notification也是其中一种方式,本文要讲解的KVO也是其中一种很轻巧的方式。
   他的实现机制为,为可能改变的数据增加一个观察者,在上面的说法中这个观察者就是controller,它去观察这个数据有没有发生变化,一旦发生变化,就会得到一个信号,从而获取到变化的数据,进行自己要做的操作。
   实例效果
   
   如上图所示,界面上设置两个label,一个显示名字,一个显示分数。还有一个按钮,用来修改分数,现在要做到点击按钮分数变化。
   可能你会觉得很简单,直接在按钮的响应方法中将分数的label内容修改不就可以了吗,确实如此,但是这里我们不这么做,而是使用KVO来完成。<喎� target="_blank" class="keylink">vcD4NCjxwPs7Sw8e0tL2o0ru49tGnyfrEo9DNo6zV4rj2xKPQzdPQwb249sr00NSjrNK7uPbOqtDVw/ujrNK7uPbOqrfWyv2ho2xhYmVs1eLKx7bByKHEo9DNtcTK/b7dwLS9+NDQz9TKvqGjPC9wPg0KPHA+z9bU2s7Sw8e4+NXiuPbKtcD9u6/By7XE0afJ+sSj0M3M7bzT0ru49rnbsuzV36OstqjS5c6qztLSqrnbsuzRp8n6xKPQzbXEt9bK/bHku6/H6b/2o6zV4sqxo6zI57n71eK49tGnyfrEo9DNtcS31sr9t6LJ+sHLseS7r6OsscjI59TasLTFpc/s06bW0Na7ttTEo9DNtcS31sr9yvTQ1L340NDQ3rjEo6xLVk/V4rj2u/rWxr7Nu+HX1LavuPi527Ls1d+3osvNzajWqqOsy7XV4rj2yvTQ1LHku6/By6OsxOPSqtf2yrLDtLLZ1/e4z7301/ahozwvcD4NCjxwPtPaysfO0sPH1Nq527Ls1d+1xEtWT7vYtfe6r8r91tC9+NDQz+DTprXEstnX96OsyOe5+87Sw8fK1bW9wcu31sr9seS7r7XEzajWqqOsxMfDtL7Nvau31sr9bGFiZWy1xNa1uPjQ3rjEzqq1scewtcS31sr9oaPV4tH5vs3Ktc/WwcvSu8zXS1ZPvPzWtbnbsuy1xMH3s8yjrLWxyLvX7rrzu7nIsdK7sr2+zcrH0saz/bnbsuzV36Ossru5/dKq1NrIt8q10OjSqtLGs/21xMqxuvLU2dLGs/2jrNLyzqrSxrP9uvO+zbK71Nm74crVtb2x5LuvtcTNqNaqwcuhozwvcD4NCjxoMSBpZD0="实现方式">实现方式
   上面例子中进行了一套KVO键值观察的流程,我们整理一下进行了哪些工作:
   设计界面样式 建立学生模型 对学生的分数属性添加观察 修改学生的分数属性 在观察到变化的响应方法中进行界面更新操作  不再需要观察的时候移除观察
   现在通过这个例子来一步步讲解。
   设计样式
   样式就不说了,两个label,一个按钮,以及按钮的响应方法,都是很常见的。
   建立模型
   这个部分,就是新建一个NSObject类,用来作为学生模型,有两个属性:姓名和分数,如下所示:
  // StudentModel.h@interface StudentModel :  NSObject @property (nonatomic, copy) NSString *name;@property float  score; @end // ViewController.m//  在controller中实例化学生模型self.studentModel = [[StudentModel alloc]  init];[self.studentModel setValue:@"Cloudox"  forKey:@"name"];[self.studentModel setValue:@"89.0"  forKey:@"score"];
   添加观察
   这一步,才是真正开始使用KVO了。
   要使用KVO,至少必须要实现两个方法:
   addObserver:forkeyPath:options:context:  observeValueForKeyPath:ofObject:change:context:
   第二个方法,就是用来获取数据变化的通知并进行相应操作的方法,这个我们后面再讲,先讲第一个方法,顾名思义,这就是用来添加观察者的方法了。
   可能你会注意到,我们上面实例化学生模型的时候,使用的是 setVlue:forKey:  的形式来设置属性值的,为什么要这样设置呢?联想到KVO的名字,键值观察,就能大概明白了,学生模型的属性名就相当于key,属性值就相当于值。
   紧接着就可以对分数来添加观察了:
   [self.studentModel addObserver:self forKeyPath:@"score"  options:NSKeyValueObservingOptionNew              context:nil];
   这里使用的就是第一个方法,有四个参数。
   第一个参数是观察者,这里被观察者是学生模型,观察者是controller,也就是self 第二个参数是keyPath,其实也就是要观察的键  第三个是一个options,这里我们写的是一个枚举值,这个地方可以填几种值,下面在进行详细的说明 第四个我们填了nil,也有其作用,下面再细说
   总之通过这行代码,我们就对score这个键,也即是分数添加了观察。
   修改数据
   在按钮的响应方法中修改学生模型的分数数据,同样使用 setVlue:forKey: 的方式进行设置。
   接收通知
   这里就用到第二个方法:observeValueForKeyPath:ofObject:change:context:
   先看看这个例子中的实现:
  // KVO回调- (void)observeValueForKeyPath:(NSString *)keyPath  ofObject:(id)object change:(NSDictionary *)change context:(void *)context {    if ([keyPath  isEqualToString:@"score"])  {        self.scoreLabel.text =  [NSString stringWithFormat:@"Score:%@", [self.studentModel  valueForKey:@"score"]];    }}
   可以看到这个回调的变化响应方法也有四个参数,其实就对应上面添加观察时的四个参数,通过keyPath,我们可以判断是不是我们想要接收的数据变化,判断它是不是score,其实也就是对不同的被观察者进行不同的操作。确实是分数变化后,我们就更新界面上的分数label,用新的分数来显示。
   移除通知
   移除通知的方法很简单,如下:
   [self.studentModel removeObserver:self  forKeyPath:@"score"];
   从观察者那边移除对被观察者特定键的观察。
   至此,一个简单的KVO流程就走完了,很简单对吧。
   进阶用法
   传递对象
   上面添加观察者和响应变化的方法中都有一个 context参数,通过这个参数可以传递一些东西,在添加观察者时设置要传递的内容,在响应变化时获得传递的内容。
   比如我要传递一个字符串,在添加观察者时设置:
   [self.studentModel addObserver:self forKeyPath:@"score"  options:NSKeyValueObservingOptionNew context:@"heyMe"];//  2.通过context传递内容给观察者
   这里在context的参数中就直接设置了要传递的对象字符串。然后在变化响应时:
   // KVO回调- (void)observeValueForKeyPath:(NSString *)keyPath  ofObject:(id)object change:(NSDictionary *)change context:(void *)context {    if ([keyPath  isEqualToString:@"score"])  {        self.scoreLabel.text =  [NSString stringWithFormat:@"Score:%@", [self.studentModel  valueForKey:@"score"]];    }    NSLog(@"%@",  context);// 通过context获取被观察者传递的内容}
   这里就可以输出context看一下,会得到传递过来的字符串内容。
   options参数
   在添加观察者时有一个options参数,在回调获取变化时有一个change参数,这两个参数其实是对应的,都是用来增加传递变化的丰富度。
   options参数可以设为:
   NSKeyValueObservingOptionOld:这表示在回调获取变化时可以通过change参数获取变化之前的值;  NSKeyValueObservingOptionNew:这表示在回调获取变化时可以通过change参数获取变化后的值;  NSKeyValueObservingOptionInitial:在添加观察者方法return的时候就发出一次通知;  NSKeyValueObservingOptionPrior:会在观察的值发生变化前发出一次通知,变化后还是会发出一次通知,所以变化一次一共会得到两次通知。
   以上就是options参数,可以看到都是对应change参数的,用来决定change参数可以得到什么样的数据,在回调获取变化时可以输出change看一下,就可以知道不同的效果了。
   change参数
   在使用change的时候可以通过下面的key来操作:
   NSKeyValueChangeKindKey:对应NSKeyValueChange的枚举值
   NSKeyValueChangeSetting = 1:说明被观察的数据的setter方法被调用了; NSKeyValueChangeInsertion  = 2:当观察的数据是集合时,且对它进行insert操作时会返回该值; NSKeyValueChangeRemoval =  3:当观察的数据是集合时,且对它进行remove操作时会返回该值; NSKeyValueChangeReplacement =  4:当观察的数据是集合时,且对它进行replace操作时会返回该值。  NSKeyValueChangeNewKey:对应options参数中的NSKeyValueObservingOptionNew,会在其中包含观察的数据变化后的新值  NSKeyValueChangeOldKey:对应options参数中的NSKeyValueObservingOptionOld,会在其中包含观察的数据变化之前得旧值  NSKeyValueChangeIndexesKey:当NSKeyValueChangeKindKey是2、3、4的时候,也就是说是观察集合数据时,这个key的值是一个NSIndexSet,包含操作对象的索引集合  NSKeyValueChangeNotificationIsPriorKey:包含一个布尔值,如果options的参数是NSKeyValueObservingOptionPrior,也就是会通知两次,在第一次通知,也就是改变前的通知时,会包含这个key
   关于这些change的值,都可以输出到控制台试一下看看是什么效果,会有更加直观的感受。
   手动通知
   之前说的都是自动通知,当添加了观察者后,只要发生改变就会自动通知观察者,但有时候我们并不是什么改变都希望得到通知,或者有时候是希望变化到什么情况后再通知,这就需要改变通知的机制。默认的实现模式为自动通知的模式,要自定义何时进行通知,就要改成手动通知的模式。
   要改成手动通知,首先要在被观察者的模型中重写一个方法 automaticallyNotifiesObserversForKey :
   // StudentModel.m+  (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key  {    BOOL automatic = NO;    if ([key  isEqualToString:@"score"])  {        automatic =  NO;    } else  {        automatic = [super  automaticallyNotifiesObserversForKey:key];    }    return  automatic;}
   这里我们在学生模型的实现文件中重写了这个方法,判断当观察的key是score分数时,就将自动通知关闭,其余的情况还是根据父类来进行判断,这样写比较保险。
   这样在我们改变学生模型的分数时,就不会自动触发通知了,要触发通知,需要自己进行设置:
   // 按钮响应- (void)changeScore {    [self  willChangeValueForKey:@"score"];//  改为手动通知    [self.studentModel setValue:@"99.0"  forKey:@"score"];    [self  didChangeValueForKey:@"score"];// 改为手动通知}
   这时就可以触发通知了,如果一个操作会触发多个属性改变,都要发通知,那么需要嵌套通知:
   // 按钮响应- (void)changeScore {    [self  willChangeValueForKey:@"name"];//  改为手动通知    [self  willChangeValueForKey:@"score"];// 改为手动通知    [self.studentModel  setValue:@"Cloud"  forKey:@"name"];    [self.studentModel  setValue:@"99.0"  forKey:@"score"];    [self  didChangeValueForKey:@"score"];//  改为手动通知    [self  didChangeValueForKey:@"name"];// 改为手动通知}
   而在一个一对多的关系中,比如集合,你必须注意不仅仅是这个key改变了,还有它改变的类型以及索引,也就是我们change中对应的几种涉及到集合的东西,如下所示:
   - (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes  {        [self  willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes  forKey:@"transactions"];            //  Remove the transaction objects at the specified  indexes.         [self  didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes  forKey:@"transactions"];}
   键值依赖
   其实关于KVO还有一个重要的点是键值依赖,也就是说一个属性的值依赖于对象中的其他属性,当那些属性变化后,这个属性的值自动被通知到进行修改,不过这个点没太弄明白,苹果给的例子有点不清不楚的,再研究一下吧。
  

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标移动开发之IOS频道!

本文由 @白羽 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved

208小时内训课程