KVO机制浅析和实例演示
什么是KVO?
KVO是Key-Value-Observing的缩写,通过KVO这种机制对象可以通过它得到其他对象的某个属性的变更通知。这种机制在MVC模式下显得更为重要,KVO可以让视图对象经过控制器观察模型对象的变更从而做出更新等操作。
KVO这一机制是基于NSKeyValueObserving协议的,Cocoa通过这个协议为所有遵循协议的对象提供了自动观察属性变化的能力。在NSObject中已经为我们实现了这一协议,所以我们不必去实现这个协议。
下图形象的表示了KVO的一种工作流程:
为什么要使用KVO?
有的朋友可能会有疑问,为什么要使用KVO呢?KVO能实现的我使用Setter方法同样能实现啊。其实不然KVO存在还是有它的价值的,那么接下来我们细数一下KVO的独特价值吧:
1.我们创建一两个setter方法感觉没什么,但是如果要观察的属性非常多,那么还能一一重写setter方法来实现吗?想必大家心里已有了答案,但是利用KVO则能很好的解决上述问题。
2.我们自定义的类是很容易改写setter方法的,但是如果你是用一个已经编译好了的类库时要监控其中一个属性时怎么办?难道还要去重写setter方法?如果使用KVO则很轻松解决问题。
3.使用KVO能够方便的记录变化前的值和变化后的值,不适用KVO你还要自己来解决这些问题。
4.KVO让你的代码看起来更加简洁清晰易于维护。
如何使用KVO呢?
首先,你要为你想观察的对象添加一个观察者代码如下:
[object addObserver: observer forKeyPath: @"frame" options: 0 context: nil];
调用方法是:
object : 被观察对象
observer: 观察对象
forKeyPath里面带上property的name,如UIView的frame、center等等
options: 有4个值,分别是:
NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
注:例子里的0就代表不带任何参数进去
context: 可以带入一些参数,任何类型都可以,强制转就可以。
接下来观察到值的变化后该应该调用相关的方法来处理,这个方法是:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
其中:
keyPath: 对应forKeyPath
object: 被观察的对象
change: 对应options里的NSKeyValueObservingOptionNew、NSKeyValueObservingOptionOld等
context: 对应context
实战代码
我们写一个学生类写一个pageview类来观察学生类中某些属性的变化并作出相关响应。
Student.h
#import <Foundation/Foundation.h> @interface Student : NSObject @property (nonatomic)NSString *name; @property (nonatomic)NSString *courseName; @property (nonatomic)double age; - (void)changeCourseName:(NSString *)newCourseName; @end Student.m
#import "Student.h" @implementation Student - (void)changeCourseName:(NSString *)newCourseName{
_courseName = newCourseName;
} @end pageView.h
#import <Foundation/Foundation.h>
#import "Student.h" @interface pageView : NSObject
- (id)init:(Student*)stu;
@end pageView.m
#import "pageView.h" @implementation pageView{
Student *student;
} - (id)init:(Student*)stu{
if(self = [super init]){
student = stu;
[stu addObserver:self
forKeyPath:@"courseName"
options:NSKeyValueObservingOptionNew
|NSKeyValueObservingOptionOld
context:nil];
[stu addObserver:self
forKeyPath:@"age"
options:NSKeyValueObservingOptionNew
|NSKeyValueObservingOptionOld
context:nil];
}
return self;
} - (void)dealloc{
[student removeObserver:self forKeyPath:@"courseName"];
} - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
if([keyPath isEqualToString:@"courseName"]){
NSLog(@"课程发生了改变");
NSLog(@"新课程是:%@ 老课程是:%@",[change objectForKey:@"new"],[change objectForKey:@"old"]);
}else if([keyPath isEqualToString:@"age"]){
NSLog(@"课程发生了改变");
NSLog(@"新课程是:%@ 老课程是:%@",[change objectForKey:@"new"],[change objectForKey:@"old"]);
}
} @end main.m
#import <Foundation/Foundation.h>
#import "Student.h"
#import "pageView.h" int main(int argc, const char * argv[])
{ @autoreleasepool { Student *student = [[Student alloc] init];
student.courseName = @"math";
student.age = ;
pageView *view = [[pageView alloc] init:student];
student.courseName = @"ddd";
student.age = ;
NSLog(@"%@",student.courseName); }
return ;
}
本文摘自,感谢作者的解释:http://www.androiddev.net/kvo/
最后对自己不懂的地方加一段补充如下,为什么必须触发属性的setter方法才能激发KVO响应函数:
解释如下(网上解释):
KVO 也许是iOS中“最神奇”的部分了,因为你不需要在被观察对象中添加任何代码,就可以实现对被观察对象属性改变的通知。KVO究竟是怎么实现的?
KVO是通过Objective-C的runtime来实现的。当你第一次要对一个对象进行观察时,runtime会为你创建一个被观察对象class的subclass。在这个新创建的subclass中,KVO会复写所要观察属性的setter方法,然后转换被观察对象的isa指针,指向新创建的subclass,所以,你想要观察的对象,变成了KVO在runtime时创建的subclass。因为Apple不想让这种机制暴露,所以还会复写要观察对象的class方法,所以,当你调用class来判断该对象的class时,还会显示原对象的class类型,而不是subclass的类型
KVO机制浅析和实例演示的更多相关文章
- C++中dynamic_cast与static_cast浅析与实例演示
1. static_cast 1.1 static_cast语法 static_cast< new_type >(expression) 备注:new_type为目标数据类型,expres ...
- KVC浅析和实例
KVC 与 KVO 是 Objective C 的关键概念,个人认为必须理解的东西,下面是实例讲解. Key-Value Coding (KVC) KVC,即是指 NSKeyValueCoding,一 ...
- Objective-C:KVO机制
KVO:key value observer 键值对的观察者 功能:给对象属性添加观察者,用来时时监测对象属性值的改变,一旦属性值发生了改变,观察者就做出相应的反应,提醒用户.在应用中,针对MVC ...
- typecho流程原理和插件机制浅析(第二弹)
typecho流程原理和插件机制浅析(第二弹) 兜兜 393 2014年04月02日 发布 推荐 1 推荐 收藏 14 收藏,3.7k 浏览 上一次说了 Typecho 大致的流程,今天简单说一下插件 ...
- Apache Thrift学习之一(入门及Java实例演示)
目录: 概述 下载配置 基本概念 数据类型 服务端编码基本步骤 客户端编码基本步骤 数据传输协议 实例演示(java) thrift生成代码 实现接口Iface TSimpleServer服务模型 T ...
- 3、使用keepalived高可用LVS实例演示
回顾: keepalived: vrrp协议的实现: 虚拟路由器: MASTER,BACKUP VI:Virtual Instance keepalived.conf GLOBAL VRRP LVS ...
- 最简实例演示asp.net5中用户认证和授权(4)
上篇: 最简实例演示asp.net5中用户认证和授权(3) 上面我们把自定义认证和授权的相关的最小基础类和要实现的接口都实现了,下面就是如何来进行认证和授权的配置. 首先我们要告诉系统,我们的用户和角 ...
- 最简实例演示asp.net5中用户认证和授权(2)
上接最简实例演示asp.net5中用户认证和授权(1) 基础类建立好后,下一步就要创建对基础类进行操作的类了,也就是实现基础类的增删改查(听起来不太高大上),当然,为了使用asp.net5的认证机制, ...
- 最简实例演示asp.net5中用户认证和授权(1)
asp.net5中,关于用户的认证和授权提供了非常丰富的功能,如果结合ef7的话,可以自动生成相关的数据库表,调用也很方便. 但是,要理解这么一大堆关于认证授权的类,或者想按照自己项目的特定要求对认证 ...
随机推荐
- RectAnimation用于在DrawingVisual画进度条
使用Visual来画图,可以使用其派生类,UIElement.Viewport3DVisual用于呈现3D内容,其他可以用来画图的为DrawingVisual,使用DrawingVisual可以使用编 ...
- HDU 3853(期望DP)
题意: 在一个r*c的网格中行走,在每个点分别有概率向右.向下或停止不动.每一步需要的时间为2,问从左上角走到右下角的期望时间. SOL: 非常水一个DP...(先贴个代码挖个坑 code: /*== ...
- C#创建桌面快捷方式 和 开机启动
/// <summary> /// 创建桌面快捷方式 2010-11-25 /// </summary> p ...
- TYVJ P1051 选课 Label:多叉转二叉&&树形dp(虐心♥)
描述 学校实行学分制.每门的必修课都有固定的学分,同时还必须获得相应的选修课程学分.学校开设了N(N<300)门的选修课程,每个学生可选课程的数量M是给定的.学生选修了这M门课并考核通过就能获得 ...
- JAVA生成RSA非对称型加密的公钥和私钥(利用JAVA API)
非对称型加密非常适合多个客户端和服务器之间的秘密通讯,客户端使用同一个公钥将明文加密,而这个公钥不能逆向的解密,密文发送到服务器后有服务器端用私钥解密,这样就做到了明文的加密传送. 非对称型加密也有它 ...
- SHell string操作 转
本文也即<Learning the bash Shell>3rd Edition的第四章Basic Shell Programming之读书笔记之二,但我们将不限于此. String操作 ...
- javascript事件大全4
javascript事件列表解说 事件 浏览器支持 解说 一般事件 onclick IE3.N2 鼠标点击时触发此事件 ondblclick IE4.N4 鼠标双击时触发此事件 onmousedown ...
- 网页制作常见的问题(怎样兼容IE6/IE7/火狐浏览器)
1.IE6双边距问题? 在IE6的浏览器中明明设置的是10px的margin却为什么显示的是20px的margin其实这个Ie6的一个双边距BUG 例如: <style type="t ...
- Html - Iframe
父页面调用子页面 //用这个对象调用子页面的函数或者dom var myiframe = $("#right_iframe")[0].contentWindow; 子页面调用父页面 ...
- Scrum会议4
组名称:天天向上 项目名称:连连看 参会成员:王森(Master)张金生 张政 栾骄阳 时间:2016.10.19 已完成内容: 1.连连看生成一关功能. 2.目前测试发现没有问题. 计划完成: 1. ...