一、什么是KVO?

KVO(key-value observing)是Objective-C对观察者设计模式的一种实现。【另一种是:通知机制(notification),详情参考:iOS 趣谈设计模式——通知】;

KVO提供一种机制,指定一个被观察的对象(A类),当对象某个属性(A中的属性name)发生更改时,对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用KVO机制】

KVO在MVC设计架构下的项目很适合实现mode模型和view视图指尖的通讯。

例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变就收到观察者收到通知,通过KVO再在控制器使用回调方法处理实现视图B的更新。

二、实现原理

KVO在Apple中的API文档如下:

Automatic key-value observing is implemented using a technique called isa-swizzling… When an observer is registered foran attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate classrather than at the trueclass…

KVO的实现依赖于Runtime,Apple的文档对于KVO机制的实现细节没有过多的描述,但是我们可以通过Runtime的所提供的发放区探索【可参考:Runtime的几个小例子】,关于KVO机制的底层实现原理:

基本原理:

1、KVO是关于runtime机制实现的

2、当某个类的对象属性第一次被观察时,系统就会在运行期动态地创建该类的一个派生类,在这个派生类中重写基类中任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制

3、如果原类为Person,那么生成的派生类名为NSKVONotifying_Person

4、每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统就会偷偷讲isa指针指向动态生成的派生类,从而在给被监控属性复制是执行的是派生类的setter方法

5、键值观察通知依赖于NSObject的两个方法:willChangeValueForKey:和didChangeValueForKey:,在一个被观察属性发生改变之前,willChangeValueForkey:和didChangeValueForKey:;在一个被观察属性发生改变之前,willChangeValueForKey:一定会被调用,这就会记录旧的值。而当改变发生后,didChangeValueForKey:会被调用,继而observeValueForKey:ofObject:change:context:也会被调用

KVO深入原理:

Apple使用了isa混写(isa-swizzling)来实现KVO。当观察对象A时,KVO机制动态创建一个新的名为NSKVONotifying_A的新类,该类集成字对象A的本类,且KVO为NSKVONotifying_A重写观察属性的setter方法,setter方法会负责在调用元setter方法之前和之后,通知所有观察对象属性值的更改情况。(备注:isa混写(isa-swizzling)isa:is a kind of ; swizzling: 混合,搅合)

1、NSKVONotifying_A类剖析:在这个过程,被观察对象的isa指针从指向原来的A类,被KVO机制修改为指向系统创建的自雷NSKVONotifying_A类,来实现当前类属性值改变的监听;

所以当我们从应用层面来看,完全没有意识到有新的类出现,这是系统“隐瞒”了对KVO的底层想实现过程,让我们误以为还是原来的类。但是此时如果我们创建一个新的名为“NSKVONotifying_A”的类,就会发现系统运行到注册KVO的那段代码时程序就崩溃,因为系统在注册监听的时候动态创建了名为NSKVONotifying_A的中间类,并指向这个中间类了。

(isa指针的作用:每个对象都有isa指针,指向该对象的类,他告诉Runtime系统这个对象的类是什么。所以对象注册为观察者时,isa指针指向新子类,那么这个被观察的对象就神奇地变成新子类的对象(或实例)了。)因而在该对象上对setter的调用就会调用已重写的setter,从而激活键值通知机制。

2、子类setter方法剖析:KVO的键值观察通知依赖与NSObject的两个方法:willChangeValueForKey:和didChangeValueForKey:,在存取数值的前后分别调用2个方法:

被观察属性发生改变之前,willChangeValueForkey:被调用,通知系统该keyPath的属性值即将变更;当改变发生后,didChangeValueForkey:被调用,通知系统该keyPath的属性值已经变更;之后,observeValueForKey:ofObject:context:也会被调用。且重写观察属性的setter方法这种继承方式的注入是在运行时而不是编译时实现的。

KVO为子类的观察者属性重写调用存取方法的工作原理在代码中相当于:

-(void)setName:(NSString*)newName{
[selfwillChangeValueForKey:@"name"];
//KVO 在调用存取方法之前总调用 
[supersetValue:newName forKey:@"name"]; 
//调用父类的存取方法 
[selfdidChangeValueForKey:@"name"];
//KVO 在调用存取方法之后总调用
}

三、特点:

观察者观察的是属性,只有遵循KVO变更属性值的方式才会执行KVO的回调方法,例如是否执行了setter方法、或者是否使用了KVC赋值。

如果赋值没有通过setter方法或者KVC,而是直接修改属性对应的成员变量,例如:仅调用_name = @"newName",这时是不会触发KVO机制,更加不会调用回调方法的。

所以使用KVO机制的前提是遵循KVO的属性设置方式来变更属性值。

【应用部分】

四、步骤

1、注册观察者,实施监听

2、在回调方法中处理属性发生的变化

3、移除观察者

五、实现方法(苹果API文档中的方法)

A.注册观察者:

//第一个参数 observer:观察者 (这里观察self.myKVO对象的属性变化)
//第二个参数 keyPath: 被观察的属性名称(这里观察 self.myKVO 中 num 属性值的改变)
//第三个参数 options: 观察属性的新值、旧值等的一些配置(枚举值,可以根据需要设置,例如这里可以使用两项)//第四个参数 context: 上下文,可以为 KVO 的回调方法传值(例如设定为一个放置数据的字典)
[self.myKVO addObserver:selfforKeyPath:@"num"options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNewcontext:nil]; 

B.属性(keyPath)的值发生变化时,收到通知,调用以下方法:

//keyPath:属性名称//object:被观察的对象
//change:变化前后的值都存储在 change 字典中
//context:注册观察者时,context 传过来的值
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary<NSString*,id> *)change context:(void*)context { }
六、上代码:


1.新建项目

UI界面设计如下:

第一个是便签,用于显示num数值,关联ViewController并命名:label;

第二个是按钮,用于改变num的数值,关联ViewController并命名为:changeNum。

2.模型创建

【新建一个File,选择Cocoa Touch Class,命名为“myKVO”,记得选择Subclass of "NSObject".】代码如下:

(myKVO.h):

@interface myKVO : NSObject

@property(nonatomic,assign) int num;//属性设置为int类型的

@end

(myKVO.m):

#import "myKVO.h"

@implementation myKVO

@synthesize num;

@end

3.在ViewController中监听并相应属性改变

(ViewController.h):

#import <UIKit/UIKit.h>

@interfaceViewController: UIViewController
@property(weak, nonatomic) IBOutletUILabel*label;//便签 label
- (IBAction)changeNum:(UIButton*)sender; //按钮事件 
@end

(ViewController.m):

#import "ViewController.h"
#import "myKVO.h"
@interfaceViewController()
@property(nonatomic,strong)myKVO *myKVO;
@end@implementationViewController
- (void)viewDidLoad { 
[superviewDidLoad]; 
self.myKVO = [[myKVO alloc]init];
/*1.注册对象myKVO为被观察者: option中, NSKeyValueObservingOptionOld 以字典的形式提供 “初始对象数据”; NSKeyValueObservingOptionNew 以字典的形式提供 “更新后新的数据”; */
[self.myKVO addObserver:selfforKeyPath:@"num"options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNewcontext:nil]; 
}
/* 2.只要object的keyPath属性发生变化,就会调用此回调方法,进行相应的处理:UI更新:*/
-(void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary<NSString*,id> *)change context:(void*)context{
// 判断是否为self.myKVO的属性“num”:
if([keyPath isEqualToString:@"num"] && object == self.myKVO) {
// 响应变化处理:UI更新(label文本改变) 
self.label.text = [NSStringstringWithFormat:@"当前的num值为:%@", [change valueForKey:@"new"]];
//change的使用:上文注册时,枚举为2个,因此可以提取change字典中的新、旧值的这两个方法
 NSLog(@"\\noldnum:%@ newnum:%@",[change valueForKey:@"old"], [change valueForKey:@"new"]);
}
/*KVO以及通知的注销,一般是在-(void)dealloc中编写。 至于很多小伙伴问为什么要在didReceiveMemoryWarning?因为这个例子是在书本上看到的,所以试着使用它的例子。 但小编还是推荐把注销行为放在-(void)dealloc中。(严肃脸

KVO实现原理和具体应用相关推荐

  1. kvo实现原理_KVC、KVO实现原理

    一.KVC运用了一个isa-swizzling技术.isa-swizzling就是类型混合指针机制.KVC主要通过isa-swizzling,来实现其内部查找定位的.isa指针,如其名称所指,(就是i ...

  2. ios kvo 要引入_iOS KVO 实现原理 和 自己实现KVO

    一:前言 KVO 是我们经常使用的键值观察者模式的一种实现 .大概功能是 比如有两个对象 A 和B  B 观察了A的某个属性E  ,当E发生变化的时候  B中收到回调 回调中 有新的 或者 旧的值 . ...

  3. kvo实现原理_KVO实现原理

    有关KVO (Key-Value Observing)大家一定不会觉得陌生,常常被用来监听某个对象属性值的改变.那么有关底层实现原理是需要来探讨的,今天就来说说KVO的基本使用以及实现原理. 什么是K ...

  4. kvo实现原理_KVO使用及实现原理

    KVO使用及实现原理 KVO使用 对属性进行监听 对属性的属性进行监听 容器监听 触发(手动触发,kvc赋值) 添加监听 // 1.kvo对属性的监听 [_person addObserver:sel ...

  5. KVC/KVO实现原理分析

    2019独角兽企业重金招聘Python工程师标准>>> 1. 函数调用(消息)实现分析: 我们看这条语句: [代码]c#/cpp/oc代码: 1 [self.person setVa ...

  6. zzz KVC/KVO原理详解及编程指南

    前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的理解. 2.由于KVO内容较少,而且是以KVC为基础实现的,本文将着重介绍KVC部分. 一.简介 KVC/KVO是观察者模 ...

  7. KVC/KVO原理详解及编程指南

    作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注 ...

  8. ios-kvc\kvo 原理

    ios-kvc\kvo 原理 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 KVC(Key-value coding)键值编 ...

  9. 探究KVO的底层实现原理

    addObserver:forKeyPath:options:context:各个参数的作用分别是什么, observer中需要实现哪个方法才能获得KVO回调? /**1. self.person:要 ...

最新文章

  1. leetcode 刷题之路 64 Construct Binary Tree from Inorder and Postorder Traversal
  2. Android中点击按钮启动另一个Activity以及Activity之间传值
  3. boost::fusion::count用法的测试程序
  4. CPU、GPU、FPGA、ASIC等AI芯片特性及对比
  5. Windows 如何用命令终端(CMD)启动和停止 MySQL 数据库服务
  6. 【MFC系列-第11天】CWinApp类成员分析
  7. 自己闲来无事做的工作日志WEB程序(VB.NET)
  8. 设计模式三(工厂方法模式)学习笔记
  9. 【NOIP2016提高A组模拟10.15】打膈膜
  10. 自主云服务器处理器_云服务器对处理器的要求
  11. Redis+Keepalived内存数据库集群配置
  12. javaee安装_JDK下载安装与环境变量配置【超详细】
  13. torch.nn.embeding
  14. delphi 简单的发送字符串消息
  15. hadoop日常维护之问题解决01
  16. 大学什么专业学matlab,我选自动化专业,该专业在大学里学些什么课程?
  17. 无法理解高等数学怎么办?
  18. java案例_面向对象编程_Stool
  19. 机器视觉:热成像相机选择的五大因素
  20. win10更新后,浏览器打开网页一直加载 甚至打不开,错误代码:ERR_TIMED_OUT

热门文章

  1. java基础_集合框架
  2. 【android UI学习】LinearGradient实现歌词滚动
  3. Java语言strcmp函数用法_蓝桥杯 算法提高 11-1实现strcmp函数 (JAVA方法)
  4. 绿色包装社会化大循环是大势所趋
  5. 数据治理--浅谈数据质量管理【从方法论、质量标准、手段、流程分析】
  6. 2013年01月29日
  7. python微信公众号爬虫_微信公众号推送信息爬取---python爬虫
  8. 咖啡——驻足、关注和聆听
  9. flutter- ListTile leading加载本地图标
  10. 【转】播放器基本原理(播放四步法)