KVO 使用及原理
KVO的基本原理大概是这样的
当一个对象被观察时, 系统会新建一个子类NSNotifying_A ,在子类中重写了对象被观察属性的 set方法, 并且改变了该对象的 isa 指针的指向(指向了新建的子类) , 当属性的值发生改变了, 会调用子类的set方法, 然后发出通知
一. KVO 的基本使用
给_person对象 添加观察者self, 当person对象的name的值发生改变的时候, 会触发observer方法
_person = [Person new]; p.name = @"oldName";
//添加观察者
// [p addObserver:self forKeyPath:@"dog" options:NSKeyValueObservingOptionNew context:nil];
[_person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
// 所观察的对象的keyPath 发生改变的时候, 会触发
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{
NSLog(@"%@",keyPath);
NSLog(@"%@",change); }
二. 当keyPath 为对象时, 改对象有许多属性, 怎么办?
在person类中,重写这个方法, 设置需要观察的属性 , 注意:"_dog.level"
//返回一个容器, 里面放的是NSString类型
+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{ NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
//观察dog对象中的所有属性
if ([key isEqualToString:@"dog"]) {
keyPaths = [keyPaths setByAddingObjectsFromArray:@[@"_dog.level",@"_dog.age"]];
} return keyPaths;
}
三. 手动触发KVO
系统默认该对象的所有属性 都能被观察到 ,重写下面方法, 可以单独设置某个属性不能被观察
//默认 yes, 默认自动观察所有属性
+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{
return YES;
}
//返回NO, 则不能被默认观察到name
+ (BOOL)automaticallyNotifiesObserversOfName{
return NO;
}
+ (BOOL)automaticallyNotifiesObserversOfAge{
return YES;
}
当 name 发生改变的时, 手动触发, 发送通知
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{
//手动发通知
//即将改变(发一次通知)
[_person willChangeValueForKey:@"name"];
_person.name = @"dddd";
//已经改变(发一次通知),一共发了两次通知
[_person didChangeValueForKey:@"name"];
}
四. 自定义KVO
根据kvo的原理, 可以自定义一个kvo, 建一个NSObject的分类, 添加方法
@interface NSObject (XSKVO) - (void)xs_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context; @end
通过runtime的方式, 动态创建一个类, 并给该类添加方法
#import "NSObject+XSKVO.h"
#import <objc/runtime.h> @implementation NSObject (XSKVO) - (void)xs_addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context{ //1.新建一个类
NSString *className = [@"XSKVO" stringByAppendingString: NSStringFromClass([self class])];
Class newClass = objc_allocateClassPair([self class], className.UTF8String, );
//注册类
objc_registerClassPair(newClass);
//2.修改 调用者类型
object_setClass(self, newClass); //3.给子类添加set方法(子类里面没有set方法的)
//OC方法:方法编号SEL ,方法实现IMP
class_addMethod(newClass, @selector(setName:), xssetName, ""); } /*
隐藏的参数:
self 方法的调用者
_cmd 方法的编号 */
void xssetName(id self,SEL _cmd, NSString *newName){
NSLog(@"自定义的实现%@",newName);
//方案一:通过消息机制 发送消息 -observeValueForKeyPath } @end
五. 其他
关于容器类(如:NSMutableArray)的观察, 当通过addObject: 向数组中添加对象, 不会触发KVO, 因为并没有触发set方法,
解决方法: 通过KVC 方法 - mutableArrayValueForKey:
KVO 使用及原理的更多相关文章
- KVO内部实现原理
KVO的原理: 只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象, (格式如:NSKVONotifying_className), 并且重写自动生成的子类对象的被监听 ...
- KVO的实现原理探寻
@import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...
- KVO底层实现原理,仿写KVO
这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Pers ...
- KVC与KVO的实现原理
|KVC的用法 1.KVC既键值编码(Key Value Coding),基于NSKeyValueCoding协议,它是以字符串的形式来操作对象的成员变量,也就是通过字符串key来指定要操作的成员变量 ...
- IOS KVO的实现原理
#import "HMViewController.h" #import "HMPerson.h" @interface HMViewController () ...
- KVC/KVO原理详解及编程指南
一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...
- 【转】 KVC/KVO原理详解及编程指南
原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的 ...
- 转:KVC/KVO原理详解及编程指南
作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 转载请注明出处 如果觉得文章对你有所帮助,请通过留言或 ...
- KVO原理解析
KVO在我们项目开发中,经常被用到,但很少会被人关注,但如果面试一些大公司,针对KVO的面试题可能如下: 知道KVO嘛,底层是怎么实现的? 如何动态的生成一个类? 今天我们围绕上面几个问题,我们先看K ...
随机推荐
- tomcat安装后,双击start.bat闪退的问题
1.jdk环境变量没有配 解决方案:我的电脑-属性-高级-环境变量,新增下面三个环境变量: ①JAVA_HOME=C:\Program Files\Java\jdk1.7.0_09(就是你jdk安装的 ...
- Openssl pkcs12命令
一.简介 pkcs12命令能生成和分析pkcs12文件 二.语法 openssl pkcs12 [-export] [-chain] [-inkey filename] [-certfile file ...
- Go语言特性
1.入口,go有且只有一个入口函数,就是main函数 liteide (IDE)的 一个工程(文件夹)只能有且只有一个main函数 package main import "fmt" ...
- 白盒测试实践项目(day6)
胡俊辉负责JUint测试部分,了解JUint测试的方法,并对其他成员介绍JUint的使用,负责JUnit部分相关文档的编写,负责博客园博客的维护,负责小组成员的任务分类与管理. 李建文负责代码复审部分 ...
- 视觉SLAM实战(一):RGB-D SLAM V2
写在前面 首先打个广告.SLAM研究者交流QQ群:254787961.欢迎各路大神和小白前来交流. 看了前面三篇博文之后,是不是有同学要问:博主你扯了那么多有用没用的东西,能不能再给力一点,拿出一个我 ...
- CodeForces 288A Polo the Penguin and Strings (水题)
题意:给定一个字符,让你用前 k 个字符把它排成 n 长度,相邻的字符不能相等,并且把字典序最小. 析:其实很简单么,我们只要多循环ab,就行,最后再把剩下的放上,要注意k为1的时候. 代码如下: # ...
- ssm集合的配置
web.xml <!DOCTYPE web-app PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN&quo ...
- 阿里云ECS搭建开源跳板机jumpserver无法获取验证邮件的问题及解决办法
这段时间自己在阿里云上搭建了jumpserver3.0,在安装过程中需要输入邮箱smtp地址,输入之后会有一封验证邮件的,但是在阿里云ECS服务器上却无法收到邮件.查阅了阿里云官方的说明: 为什么无法 ...
- HTML中的内容总结
一.URL编码类型 对于Get方法,参数是直接通过URL传递的,那这个参数又是根据什么进行编码的呢?对于JSP网页,这个编码是通过第一句描述: <%@ page language="j ...
- 浅谈HTTPS以及Fiddler抓取HTTPS协议(摘抄)
一.浅谈HTTPS 我们都知道HTTP并非是安全传输,在HTTPS基础上使用SSL协议进行加密构成的HTTPS协议是相对安全的.目前越来越多的企业选择使用HTTPS协议与用户进行通信,如百度.谷歌等. ...