刨根问底KVO
KVO 全称 Key-Value Observing。中文叫键值观察。KVO其实是一种观察者模式,观察者在键值改变时会得到通知,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。相比Notification,KVO更加的简单直接。
KVO的操作方法由NSKeyValueCoding提供,而他是NSObject的类别,也就是说ObjC中几乎所有的对象都支持KVO操作。
KVO的使用也很简单,就是简单的3步。
- 注册需要观察的对象的属性addObserver:forKeyPath:options:context:
- 实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用.在这个方法中还通过NSKeyValueObservingOptionNew这个参数要求把新值在dictionary中传递过来。
- 取消注册观察removeObserver:forKeyPath:context:
我们观察下代码实现,探究实现原理:
Person.h
1
|
#import <Foundation/Foundation.h>
|
Person.m
1
|
#import "Person.h"
|
main函数
1
|
Person * p = [[Person alloc] init];
|
运行程序打印出的log日志为:
1
|
Person,20
|
不要太惊讶,我们慢慢解释。
我重写的Person
类的description
方法,使用KVC拿到isa
指针,获取到self的类名,我们发现在使用KVO之前类名是Person
,但注册了KVO之后,类名变成了NSKVONotifying_Person
。
主要是因为KVO的实现使用了isa-swizzling
。在程序运行时Person
会生成一个派生类NSKVONotifying_Person
,在这个派生类中重写基类中任何被观察属性的setter
方法,用来欺骗系统顶替原先的类。在setter
方法中实现真正的通知机制.
1
|
//可以到伪代码
|
我们又可以猜测,使用KVO,内部一定执行setter方法。
当我们把上面代码 p.age = 30;
改成p->_age = 30;
你会发现KVO的方法不走了,也证实了这点。
如果p不提供setAge,getAge方法,还想用KVO.
1
|
[p willChangeValueForKey:@"age"];
|
苹果官方KVO文档:
另外.....
我的愿望是.......
世界和平.........
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:iOS设计模式 —— KV0 - Python技术站