KVO的底层实现原理?如何取消系统默认的KVO并手动触发?
- KVO是基于runtime机制实现的
- 当某个类的属性对象
第一次被观察
时,系统就会在运行期动态
地创建该类的一个派生类(该类的子类)
,在这个派生类中重写基类中任何被观察属性的setter 方法。派生类在被重写的setter方法内实现真正的通知机制
- 如果原类为Person,那么生成的派生类名为
NSKVONotifying_Person
- 每个类对象中都有一个isa指针指向当前类,当一个类对象的第一次被观察,那么系统会偷偷将isa指针指向动态生成的派生类,从而在给被监控属性赋值时执行的是派生类的setter方法
- 键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
- 补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类
// 添加对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"]; } } |
最新文章
- vm10.0key
- Odoo Website 替换 谷歌地图为 百度地图
- 在Linux里设置环境变量的方法(export PATH)
- HDU 5313 Bipartite Graph
- C socket demo
- 关于gcc的一点小人性化提示
- python 的__init__ 和__new__ 区别
- 前端 ---JS中的面向对象
- Spring容器技术内幕之BeanDefinition类介绍
- VisualStudio2008+水晶报表的使用
- C# DataTable 通过Linq分组
- C++11 delete和default
- hive 分区表
- Linux服务-NFS
- Memory Analyzer tool(MAT)分析内存泄漏---理解Retained Heap、Shallow Heap、GC Root
- VS------csc.exe已停止工作解决方法
- VS2010/MFC编程入门之三十(常用控件:树形控件Tree Control 上)
- 前端开发 - HTML - 简介
- [Leetcode] pascals triangle ii 帕斯卡三角
- Hadoop学习笔记(3) Hadoop文件系统二