KVO的底层实现原理?如何取消系统默认的KVO并手动触发?

摘要:
KVO是基于运行时机制实现的。当第一次观察到类的属性对象时,系统将在运行时动态创建该类的派生类(类的子类),并重写该派生类中基类中任何观察到的属性的setter方法。派生类在重写的setter方法中实现了真正的通知机制。如果原始类是Person,则生成的派生类名为NSKVONotifying_Person每个类对象都有一个指向当前类的isa指针。首次观察类对象时
  • KVO是基于runtime机制实现的
  • 当某个类的属性对象第一次被观察时,系统就会在运行期动态地创建该类的一个派生类(该类的子类),在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
  • 如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
  • 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
  • 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
  • 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类 KVO的底层实现原理?如何取消系统默认的KVO并手动触发?第1张

// 添加对Account的监听

        [self.account addObserver:self forKeyPath:@"balance" options:NSKeyValueObservingOptionNew context:nil];

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context{

    if([keyPath isEqualToString:@"balance"]){

        NSLog(@"keyPath=%@,object=%@,newValue=%.2f,context=%@",keyPath,object,[[change objectForKey:@"new"] floatValue],context);

    }

}

-(void)dealloc{

    [self.account removeObserver:self forKeyPath:@"balance"];  //移除监听

}

修改使用方法,可实现取消系统kvo,自己触发,也就可控。

+(BOOL)automaticallyNotifiesObserversForKey:(NSString *)key{

    if ([key isEqualToString:@"name"]) {

        return NO;

    }else{

        return [super automaticallyNotifiesObserversForKey:key];

    }

}

-(void)setName:(NSString *)name{

    

    if (_name!=name) {

        

        [self willChangeValueForKey:@"name"];

        _name=name;

        [self didChangeValueForKey:@"name"];

    }

    

}

免责声明:文章转载自《KVO的底层实现原理?如何取消系统默认的KVO并手动触发?》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇C++ list容器系列功能函数详解Java 8 的 Metaspace下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

在.net core中数据操作的两种方式(Db first &amp;amp;&amp;amp; Code first)

在开发过程中我们通常使用的是Db first这种模式,而在.net core 中推荐使用的却是 code first 反正我是很不习惯这种开发模式 于是就搜寻整个微软的官方文档,终于找到了有关.net core 使用Db first 的教程,这里给出链接:https://docs.microsoft.com/zh-cn/ef/core/miscellane...

Android自定义组合控件

今天和大家分享下组合控件的使用。很多时候android自定义控件并不能满足需求,如何做呢?很多方法,可以自己绘制一个,可以通过继承基础控件来重写某些环节,当然也可以将控件组合成一个新控件,这也是最方便的一个方法。今天就来介绍下如何使用组合控件,将通过两个实例来介绍。第一个实现一个带图片和文字的按钮,如图所示: 整个过程可以分四步走。第一步,定义一个lay...

prometheus学习笔记(2)-利用java client写入数据

继续学习prometheus,上一节演示了用http方式使用curl向pushgateway发送数据,本节将研究如何利用client jar包,以java代码的方式写入数据。 一、依赖的jar包 1 <dependency> 2 <groupId>io.prometheus</groupId> 3...

ASP.NET Core WebAPI学习-1

Web API学习 ASP.NET Core WebAPI学习-1 ASP.NET Core WebAPI学习-2 ASP.NET Core WebAPI学习-3 ASP.NET Core WebAPI学习-4 ASP.NET Core WebAPI学习-5 ASP.NET Core WebAPI学习-6 创建Web API项目 打开Visual...

SpringBoot启动过程中涉及到了扩展接口

SpringApplicationRunListener接口 1、ApplicationListener接口 是ApplicationContext的事件监听器 2、EnvironmentPostProcessor接口 上下文环境后置处理器,事件中调用 3、PropertySourceLoader接口 自定义配置文件加载器,自己解析配置文件属性...

Android 自己实现更新下载自动安装

1、一些公司开发完一款App之后可能并不会去上架App商店,但事后期也需要定时进行维护更新,所以会选择把打包好的apk 发布到自己的服务器,然后在数据库建一个版本号的表,然后剩下的就交给你android开发了,android自己要实现版本检测更新,由于android自带的DownloadManager 就可以实现下载功能,用起来就会很简单了,不用再写很多下...