目录

  • 概念

  • 应用KVO的3个步骤

  • 关联属性的KVO

  • 手动管理KVO通知

一、概念

  KVO全称是 Key-Value Observing ,是OC的一种消息发送机制。这个机制是指:假设将B对象注册为A对象的观察者,当A对象的属性发生改变时就会通知它自己的所有观察者包括对象B在内。

  KVO一般用于Controller与Model之间的通信。常见的做法是把Controller注册为Model的观察者,当model改变时Controller就会收到通知并根据新的model来更新View。

  KVO是基于KVC技术的,所以为了理解KVO你必须先了解KVC(还不了解的请移步)。

  需要注意的是,只有两个方式改变对象的属性才会触发KVO通知

    1.通过KVC方法改变(setValue:forKey,setValue:forKeyPath)

    2.通过setter函数(.操作符会调用setter)

  当然你也可以手动管理KVO通知,我们在下面将会讲到

二、应用KVO的3个步骤

  1. 为被观察者注册一个观察者
  2. 观察者接收属性改变的通知
  3. 移除观察者

  1.注册观察者  

//这句代码的意思是 self.observing 观察 self.observed的age属性
[self.observed addObserver:self.observing forKeyPath:@"age" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

  2.接收通知

  在观察者类实现下面方法,当被观察的对象的属性改变时KVO就会调用这个方法。

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{

    NSLog(@"%@ : [%@] => [%@]",keyPath,[change valueForKey:NSKeyValueChangeOldKey],[change valueForKey:NSKeyValueChangeNewKey]);

}

  3.移除观察者

  因为注册观察者时,被观察者就持有观察者的强引用,这有这样才能在属性改变时通知观察者。

[self.observed removeObserver:self.observing forKeyPath:@"age"];

  我可以这样有下面代码改变属性,触发KVO通知

// setter
[self.observed setAge:@];
// kvc
[self.observed setValue:@ forKey:@"age"];

  如果不出意外应该会输出如果log

age : [] => []
age : [] => []

三、关联属性的KVO  

  关联的属性分为两种情况,一对多,多对多

  多对多情况,我们只能通过手动触发KVO等方式来处理

  下面我们来介绍一对多的情况。

  假设Person类有一个readonly的属性 fullName,这个fullName有firstName和lastName组成,下面是fullName的getter函数

-(NSString *)fullName{
return [NSString stringWithFormat:@"%@ %@",self.firstName,_lastName];
}

  我们希望当改变firstName或者lastName时可以触发fullName的kvo通知以便告诉其他人,他人只要观察fullName属性就可以了而不需要分别观察firstName跟lastName。

  我们可以有如下函数之一来告诉fullName与fristName、lastName的关联关系

// 单个对象的属性 1
+(NSSet *)keyPathsForValuesAffectingFullName{
return [NSSet setWithArray:@[@"firstName",@"lastName"]];
}
// 单个对象的属性 2
+(NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
if ([key isEqualToString:@"fullName"]) {
NSArray *affectingKeys = @[@"lastName", @"firstName"];
keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
}
return keyPaths;
}

四、手动管理KVO通知

  普通的对象之所以拥有KVO的功能是因为我们的对象都是继承自NSObject类的。

  NSObject帮我实现了一些函数, KVO在适当的时候通过调用这些函数来完成KVO功能。

  其中包过下面两个函数

-(void)willChangeValueForKey:(NSString *)key;
-(void)didChangeValueForKey:(NSString *)key;

  我们正式通过自己调用这两个函数来控制KVO的通知的发送,当我们想手动触发age属性的KVO通知时可以这样写:

[self willChangeValueForKey:@"age"];
_age = ;
[self didChangeValueForKey:@"age"];

  当然,最后你得告诉oc说你自己来管理KVO通知

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
if ([theKey isEqualToString:@"age"]) {
return NO;
}
}

KVO 开发详情的更多相关文章

  1. ARC中KVO开发注意

    1 在ARC 中 KVO开发 添加监听和去掉监听必需 一一匹配,不要有过的去掉监听否则会有可能导致对象无法释放. 例如,在一个viewcontroller中添加webview 并监听webview的c ...

  2. objective-c runtime 开发详情

    目录 概述 对象与类的实质 id与class 继承关系与isa 总结 C函数创建一个OC类 OC类与runtime NSObjectProtocol NSObject NSProxy 一.概述 Obj ...

  3. iOS 定时器开发详情

    目录 概述 NSTimer performSelector GCD timer CADisplayLink 一.概述 在平时的开发任务中,定时器是我们常用的技术.这一节我们来学习iOS怎么使用定时器. ...

  4. KVC 开发详情

    目录 概述 KVC基本技术 KVC访问函数 KVC搜索顺序 KVC集合操作 一.概述 kvc全名是Key-value coding,kvc是一种通过字符串间接的访问oc对象的属性的一种技术. 一个oc ...

  5. GCD 开发详情

    目录 一.简介 二.dispatch Queue - 队列 三.dispatch Groups - 组 四.dispatch Semaphores - 信号量 五.dispatch Barriers ...

  6. 如何开发Android Wear应用程序

    Android Wear是连接安卓手机和可穿戴产品的一个平台.自从今年上半年发布以来,Android Wear获得了大量关注,既有来自消费者的关注,也有来自开发商的关注,后者希望自己的应用程序已经准备 ...

  7. 微信小程序开发-概述

    微信小程序开发-概述 一.小程序申请&APPID 登录微信平台申请成为小程序开发者,小程序不可直接使用服务号或订阅号的AppID,需要登录微信公众平台管理后台,在网站的"设置&quo ...

  8. jeecms v9开发资料

    开发文档 . 系统架构概述 本系统核心架构为 FreeMarker+hibernate+Spirng 的 mvc 分层架构. 1.1 分层架构模型 img 1.2 数据流转模型 (前端) img . ...

  9. 教你如何开发一个完败Miracast的投屏新功能

      手机与电视,是陪伴在我们生活最常见,陪伴最长久的智能设备.迅猛发展的移动终端与通信技术,赋予了手机更广阔多元的应用生态,大屏电视则以大视野和震撼影音,弥补了手里方寸带来的视觉局限.而今,手机的延伸 ...

随机推荐

  1. 路由器基础配置之dhcp配置

    我们将以上面的拓扑图为例,router9为dhcp的服务器,为pc4,5,6分配三个不同网段的地址,pool为要分配的三个地址池,我们要把pc4设置为12网段,pc5设置成34网段,pc6设置成56网 ...

  2. C#在textBox中输出一个数组

    //将数组输出到文本框测试 for(i=0;i<arr.Length-1;i++){ this.textBox1.Text=this.textBox1.Text+arr[i]; }

  3. C# 用HttpWebRequest模拟一个虚假的IP伪造ip

    有人会说:IP验证是在TCP层完成的,不是HTTP层完成的,如果伪造IP的话可能连TCP的三次握手都完不成.我这里说的不是完全意义的伪造.如果你使用透明代理上网,那么在透明代理发送给服务器端的HTTP ...

  4. Discuz论坛搜索下拉框插件openSug

    Discuz!只需安装openSug插件即可获得带有“搜索框提示”功能的搜索框,让您的Discuz搜索更便捷! 下载:https://www.opensug.org/faq/.../opensug.d ...

  5. Mysql错误积累001-load data导入文件数据出现1290错误

    错误出现情景 在cmd中使用mysql命令,学生信息表添加数据.使用load data方式简单批量导入数据. 准备好文本数据: xueshengxinxi.txt 文件  数据之间以tab键进行分割 ...

  6. python更新mysql数据

    >>>cur.execute("update users set username=%s where id=2",("mypython")) ...

  7. docker和docker compose常用操作命令

    首先区分一下docker中几个概念 Image:镜像,相当于一个root文件系统,不包含任何动态数据 Container:容器,镜像运行时的实体,实质是进程,容器进程运行于属于自己的独立的命名空间 d ...

  8. 贪心算法之Kruskal

    克鲁斯卡尔Kruskal算法同Prim算法一样,都是求最小生成树.Kruskal是不断的找最短边,加入集合,且不构成回路. 所以,我们可以给每个点定义一个集合,一边的起点和终点查看是否属于同一集合,如 ...

  9. Java——equals方法---18.10.18

    一.equals方法定义 public boolean equals(Object obj)方法 //提供对象是否“相等”的逻辑 二.”equals“和“==”的区别 1.“==”比较的是两个变量本身 ...

  10. php curl 登陆百度贴吧(经历记录)

    这两天,因为公司需要,所以研究了一下百度文库的登陆方案.因为账号是购买的,只有一部分cookie值,所以不能通过正常的渠道登陆,所以只有通过curl模拟直接进行后台登陆.那么,问题来了.按照人家说的, ...