目录

  • 概念

  • 应用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. LintCode 7.Serialize and Deserialize Binary Tree(含测试代码)

    题目描述 设计一个算法,并编写代码来序列化和反序列化二叉树.将树写入一个文件被称为“序列化”,读取文件后重建同样的二叉树被称为“反序列化”. 如何反序列化或序列化二叉树是没有限制的,你只需要确保可以将 ...

  2. docker API 配置与使用

    在网上看到一大堆乱乱七八招的博客,很多都不能用,我根据这些天踩的坑来总结一下吧 首先!怎么配置 docker API 两种方法 在/etc/sysconfig/docker文件里加一行OPTIONS= ...

  3. jQuery(三)HTML

    获得内容: text() - 设置或返回所选元素的文本内容 html() - 设置或返回所选元素的内容(包括 HTML 标记) val() - 设置或返回表单字段的值 <html> < ...

  4. [转]ThinkPHP5 隐藏index.php问题

    ThinkPHP5 隐藏index.php问题 Apache,修改.htaccess文件 ----------------------------------------------------- R ...

  5. java泛型<? extends E> 有上限通配符与<? Super E>有上限通配符

    通配符?,?表示占位,表明将来使用的时候在指明类型 <?>无限定的通配符, 是让泛型能够接受未知类型的数据 <? extends E> 有上限通配符,能够接受指定类及其子类类型 ...

  6. ABAP CDS ON HANA-(7)CDSビューでの集約

    Aggregate expression in CDS View An aggregate expression calculates a single value from an operand o ...

  7. 【转】mui 通过JSON动态的生成列表

    <script type="text/template" id="radio-tigan"> <%for(var i=0;i<recor ...

  8. RHCE7认证学习笔记17——KickStart安装系统

    一.自动化安装系统工具 1.Cobbler    另一个自动化安装工具: 2.Kickstart 二.使用kickstart自动化安装系统 服务器安装的软件: 1.dhcp服务   [root@lin ...

  9. PRO*C 函数事例 3 -- 游标使用

    1.Oracle中的游标    Oracle使用两种游标: 显式游标和隐式游标. 不管语句返回多少条记录, Oracle为每条使用的SQL语句隐式地定义一个游标. Oracle为每个DELETE , ...

  10. Python正则反向引用

    str2 ="2018-10-29"c =re.sub(r"(\d{4})-(\d{2})-(\d{2})","\g<1>/\g<2 ...