摘要:本文将带你了解IOS开发入门iOS键值观察KVO实例详解,希望本文对大家学IOS有所帮助。
本文将带你了解IOS开发入门iOS键值观察KVO实例详解,希望本文对大家学IOS有所帮助。
简介
什么是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
可以看到这个回调的变化响应方法也有四个参数,其实就对应上面添加观察时的四个参数,通过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
这里就可以输出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频道!
您输入的评论内容中包含违禁敏感词
我知道了
请输入正确的手机号码
请输入正确的验证码
您今天的短信下发次数太多了,明天再试试吧!
我们会在第一时间安排职业规划师联系您!
您也可以联系我们的职业规划师咨询:
版权所有 职坐标-一站式IT培训就业服务领导者 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
沪公网安备 31011502005948号