KVO实现原理和具体应用
一、什么是KVO?
KVO(key-value observing)是Objective-C对观察者设计模式的一种实现。【另一种是:通知机制(notification),详情参考:iOS 趣谈设计模式——通知】;
KVO提供一种机制,指定一个被观察的对象(A类),当对象某个属性(A中的属性name)发生更改时,对象会获得通知,并作出相应处理;【且不需要给被观察的对象添加任何额外代码,就能使用KVO机制】
KVO在MVC设计架构下的项目很适合实现mode模型和view视图指尖的通讯。
例如:代码中,在模型类A创建属性数据,在控制器中创建观察者,一旦属性数据发生改变就收到观察者收到通知,通过KVO再在控制器使用回调方法处理实现视图B的更新。
二、实现原理
KVO在Apple中的API文档如下:
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为子类的观察者属性重写调用存取方法的工作原理在代码中相当于:
三、特点:
观察者观察的是属性,只有遵循KVO变更属性值的方式才会执行KVO的回调方法,例如是否执行了setter方法、或者是否使用了KVC赋值。
如果赋值没有通过setter方法或者KVC,而是直接修改属性对应的成员变量,例如:仅调用_name = @"newName",这时是不会触发KVO机制,更加不会调用回调方法的。
所以使用KVO机制的前提是遵循KVO的属性设置方式来变更属性值。
【应用部分】
四、步骤
1、注册观察者,实施监听
2、在回调方法中处理属性发生的变化
3、移除观察者
五、实现方法(苹果API文档中的方法)
A.注册观察者:
B.属性(keyPath)的值发生变化时,收到通知,调用以下方法:
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>
(ViewController.m):
KVO实现原理和具体应用相关推荐
- kvo实现原理_KVC、KVO实现原理
一.KVC运用了一个isa-swizzling技术.isa-swizzling就是类型混合指针机制.KVC主要通过isa-swizzling,来实现其内部查找定位的.isa指针,如其名称所指,(就是i ...
- ios kvo 要引入_iOS KVO 实现原理 和 自己实现KVO
一:前言 KVO 是我们经常使用的键值观察者模式的一种实现 .大概功能是 比如有两个对象 A 和B B 观察了A的某个属性E ,当E发生变化的时候 B中收到回调 回调中 有新的 或者 旧的值 . ...
- kvo实现原理_KVO实现原理
有关KVO (Key-Value Observing)大家一定不会觉得陌生,常常被用来监听某个对象属性值的改变.那么有关底层实现原理是需要来探讨的,今天就来说说KVO的基本使用以及实现原理. 什么是K ...
- kvo实现原理_KVO使用及实现原理
KVO使用及实现原理 KVO使用 对属性进行监听 对属性的属性进行监听 容器监听 触发(手动触发,kvc赋值) 添加监听 // 1.kvo对属性的监听 [_person addObserver:sel ...
- KVC/KVO实现原理分析
2019独角兽企业重金招聘Python工程师标准>>> 1. 函数调用(消息)实现分析: 我们看这条语句: [代码]c#/cpp/oc代码: 1 [self.person setVa ...
- zzz KVC/KVO原理详解及编程指南
前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的理解. 2.由于KVO内容较少,而且是以KVC为基础实现的,本文将着重介绍KVC部分. 一.简介 KVC/KVO是观察者模 ...
- KVC/KVO原理详解及编程指南
作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或关注 ...
- ios-kvc\kvo 原理
ios-kvc\kvo 原理 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 KVC(Key-value coding)键值编 ...
- 探究KVO的底层实现原理
addObserver:forKeyPath:options:context:各个参数的作用分别是什么, observer中需要实现哪个方法才能获得KVO回调? /**1. self.person:要 ...
最新文章
- leetcode 刷题之路 64 Construct Binary Tree from Inorder and Postorder Traversal
- Android中点击按钮启动另一个Activity以及Activity之间传值
- boost::fusion::count用法的测试程序
- CPU、GPU、FPGA、ASIC等AI芯片特性及对比
- Windows 如何用命令终端(CMD)启动和停止 MySQL 数据库服务
- 【MFC系列-第11天】CWinApp类成员分析
- 自己闲来无事做的工作日志WEB程序(VB.NET)
- 设计模式三(工厂方法模式)学习笔记
- 【NOIP2016提高A组模拟10.15】打膈膜
- 自主云服务器处理器_云服务器对处理器的要求
- Redis+Keepalived内存数据库集群配置
- javaee安装_JDK下载安装与环境变量配置【超详细】
- torch.nn.embeding
- delphi 简单的发送字符串消息
- hadoop日常维护之问题解决01
- 大学什么专业学matlab,我选自动化专业,该专业在大学里学些什么课程?
- 无法理解高等数学怎么办?
- java案例_面向对象编程_Stool
- 机器视觉:热成像相机选择的五大因素
- win10更新后,浏览器打开网页一直加载 甚至打不开,错误代码:ERR_TIMED_OUT