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 使用及原理的更多相关文章

  1. KVO内部实现原理

    KVO的原理: 只要给一个对象注册一个监听, 那么在运行时, 系统就会自动给该对象生成一个子类对象, (格式如:NSKVONotifying_className), 并且重写自动生成的子类对象的被监听 ...

  2. KVO的实现原理探寻

    @import url(http://i.cnblogs.com/Load.ashx?type=style&file=SyntaxHighlighter.css);@import url(/c ...

  3. KVO底层实现原理,仿写KVO

    这篇文章简单介绍苹果的KVO底层是怎么实现的,自己仿照KVO的底层实现,写一个自己的KVO监听 #pragma mark--KVO底层实现 第一步:新建一个Person类继承NSObject Pers ...

  4. KVC与KVO的实现原理

    |KVC的用法 1.KVC既键值编码(Key Value Coding),基于NSKeyValueCoding协议,它是以字符串的形式来操作对象的成员变量,也就是通过字符串key来指定要操作的成员变量 ...

  5. IOS KVO的实现原理

    #import "HMViewController.h" #import "HMPerson.h" @interface HMViewController () ...

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

    一.简介 1.KVC简介 2.KVO简介 二.KVC相关技术 1.Key和Key Path 2.点语法和KVC 3.一对多关系(To-Many)中的集合访问器方法 4.键值验证(Key-Value V ...

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

    原文地址:http://blog.csdn.net/wzzvictory/article/details/9674431 前言: 1.本文基本不讲KVC/KVO的用法,只结合网上的资料说说对这种技术的 ...

  8. 转:KVC/KVO原理详解及编程指南

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

  9. KVO原理解析

    KVO在我们项目开发中,经常被用到,但很少会被人关注,但如果面试一些大公司,针对KVO的面试题可能如下: 知道KVO嘛,底层是怎么实现的? 如何动态的生成一个类? 今天我们围绕上面几个问题,我们先看K ...

随机推荐

  1. [BAT] 通过批处理加host

    echo. >> %WINDIR%\system32\drivers\etc\hosts & echo xxx.xxx.xxx.xx test_host >> %WIN ...

  2. Greeplum 系列(二) 安装部署

    Greeplum 系列(二) 安装部署 本章将介绍如何快速安装部署 Greenplum,以及 Greenplum 的一些常用命令及工具.本章不会涉及硬件选型.操作系统参数讲解.机器性能测试等高级内容, ...

  3. NHibernate获取实体配置信息(表名,列名等等)

    // 注意这里有个&符号,并不是写错了,而是约定 就是这样写的ctx.GetObject("&SessionFactory") 这是官网地址http://nhfor ...

  4. Java中的Set,List,Map的区别

    1. 对JAVA的集合的理解是想对于数组 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型) JAVA集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 ja ...

  5. 斐波那契数列—java实现

    最近在面试的时候被问到了斐波那契数列,而且有不同的实现方式,就在这里记录一下. 定义 斐波那契数列指的是这样一个数列 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, ...

  6. NBA常识 位置的划分 足球:越位等于抢跑

    篮球:1号位——组织后卫(控球,组织)2号位——得分后卫(中远投篮,突破)3号位-----小前锋(突破,中远投篮)4号位——大前锋(二中锋,篮板,背身单打,禁区防守)5号位——中锋(篮板.背身单打,禁 ...

  7. 设计模式18:Observer 观察者模式(行为型模式)

    Observer 观察者模式(行为型模式) 动机(Motivation) 在软件构建过程中,我们需要为某些对象建立一种“通知依赖关系”——一个对象(目标对象)的状态发生改变,所有依赖对象(观察者对象) ...

  8. centos 学习总结

    我用的是6.4 添加中文输入法 .su root .yum install "@Chinese Support" .exit .回到桌面,system->preference ...

  9. Oracle定時email通知

    small_program_task 這張表的資料是待發送的email通知,再次之前已經有一個job會定時掃描固定時間內未接收到小程式回報狀態將其寫入到該表,send_flag為N,表示為寄過通知.e ...

  10. PMBOK项目管理思维导图梳理

    采用思维导图的形式来展示项目管理的五大过程组.九大知识领域,能更好的展示框架结构,便于理解.分析. 下图为思维导图化制的项目管理要素:灰色为启动过程组.白色为规划过程组.紫色为执行过程组.蓝色为监控过 ...