KVO实现原理
来源:互联网 发布:质检总局网络培训学院 编辑:程序博客网 时间:2024/05/21 17:56
http://www.bjbkws.com/apply/1210/
什么是KVO ?
KVO即Key-Value Observing,它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。
简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了。
KVO(Key Value Observing),是观察者模式在Foundation中的实现。
KVO的原理
简而言之就是:
1、当一个object有观察者时,动态创建这个object的类的子类
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类
简单验证下。
@interface Sark : NSObject
@property (nonatomic, copy) NSString *name;
@end
@implementation Sark
@end
Sark *sark = [Sark new];
// breakpoint 1
[sark addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew context:nil];
// breakpoint 2
sark.name = @"萨萨萨";
[sark removeObserver:self forKeyPath:@"name"];
// breakpoint 3
断住后分别使用- class和object_getClass()打出sark对象的Class和真实的Class
// breakpoint 1
(lldb) po sark.class
Sark
(lldb) po object_getClass(sark)
Sark
// breakpoint 2
(lldb) po sark.class
Sark
(lldb) po object_getClass(sark)
NSKVONotifying_Sark
// breakpoint 3
(lldb) po sark.class
Sark
(lldb) po object_getClass(sark)
Sark
上面的结果说明,在sark对象被观察时,framework使用runtime动态创建了一个Sark类的子类NSKVONotifying_Sark,而且为了隐藏这个行为,NSKVONotifying_Sark重写了- class方法返回之前的类,就好像什么也没发生过一样。但是使用object_getClass()时就暴露了,因为这个方法返回的是这个对象的isa指针,这个指针指向的一定是个这个对象的类对象
然后来偷窥一下这个动态类实现的方法,这里请出一个NSObject的扩展NSObject+DLIntrospection,它封装了打印一个类的方法、属性、协议等常用调试方法,一目了然。
@interface NSObject (DLIntrospection)
+ (NSArray *)classes;
+ (NSArray *)properties;
+ (NSArray *)instanceVariables;
+ (NSArray *)classMethods;
+ (NSArray *)instanceMethods;
+ (NSArray *)protocols;
+ (NSDictionary *)descriptionForProtocol:(Protocol *)proto;
+ (NSString *)parentClassHierarchy;
@end
然后继续在刚才的断点处调试:
// breakpoint 1
(lldb) po [object_getClass(sark) instanceMethods]
<__NSArrayI 0x8e9aa00>(
- (void)setName:(id)arg0 ,
- (void).cxx_destruct,
- (id)name
)
// breakpoint 2
(lldb) po [object_getClass(sark) instanceMethods]
<__NSArrayI 0x8d55870>(
- (void)setName:(id)arg0 ,
- (class)class,
- (void)dealloc,
- (BOOL)_isKVOA
)
// breakpoint 3
(lldb) po [object_getClass(sark) instanceMethods]
<__NSArrayI 0x8e9cff0>(
- (void)setName:(id)arg0 ,
- (void).cxx_destruct,
- (id)name
)
大概就是说arc下这个方法在所有dealloc调用完成后负责释放所有的变量,当然这个和KVO没啥关系了,回到正题。
从上面breakpoint2的打印可以看出,动态类重写了4个方法:
1、- setName:最主要的重写方法,set值时调用通知函数
2、- class隐藏自己必备啊,返回原来类的class
3、- dealloc做清理犯罪现场工作
4、- _isKVOA这就是内部使用的标示了,判断这个类有没被KVO动态生成子类
接下来验证一下KVO重写set方法后是否调用了- willChangeValueForKey:和- didChangeValueForKey:
最直接的验证方法就是在Sark类中重写这两个方法:
@implementation Sark
- (void)willChangeValueForKey:(NSString *)key
{
NSLog(@"%@", NSStringFromSelector(_cmd));
[super willChangeValueForKey:key];
}
- (void)didChangeValueForKey:(NSString *)key
{
NSLog(@"%@", NSStringFromSelector(_cmd));
[super didChangeValueForKey:key];
}
@end
- 解析KVO实现原理
- 解析KVO实现原理
- 解析KVO实现原理
- KVO的实现原理
- KVO实现原理探究
- KVO底层实现原理
- KVO底层实现原理
- KVO实现原理
- KVO实现原理
- KVO实现原理
- 解析KVO实现原理
- KVO实现原理
- KVO的实现原理
- KVO实现原理
- KVO实现原理
- KVO的实现原理
- KVO 的实现原理
- iOS KVO 实现原理
- PowerDesigner(四)-业务处理模型
- 第三次实验
- 4.3.2.1 master_avail_listen函数:挂载或卸载回调函数master_avail_event
- Webrtc IOS下载编译文档
- 如何多方位布局程序化购买生态链条?
- KVO实现原理
- javascript:localStorage的兼容性实现
- c++作业2-标准体重,两点距离,模拟ATM
- MySQL数据类型格式及长度
- ORACLE
- Java命令运行错误
- PowerDesigner(五)-概念数据模型(CDM生成LDM,PDM和OOM)
- PHP中的三种基本设计模式
- Gson转换json串到Map,Key值是String还是设定值(如Long)?