IOS中的KVO机制详解
来自: http://my.oschina.net/shiyuecamus/blog/626136
ios开发有多种设计模式,其中有一种就叫做观察者模式,即Key Value Observing(简称KVO)
KVO是Object -C中原声支持的一种机制.
C、KVO 实现原理
当对一个对象添加观察者,被观察对象的属性值发生变化时,观察者会得到通知,并对变化做出相应的处理。
D、KVO 的特性
1. 支持多个观察者观察同一属性,也支持一个观察者监听不同属性。
2. 利用它可以很容易地实现视图和数据模型的分离,当数据模型的属性值改变之后,作为监听器的视图就会被激发,并回调监听器自身的监听方法。
3. 对于KVC的基本的方法都定义在 NSKeyValueCoding 的非正式协议中,并且NSObject默认实现了该协议。相对的,在ObjC中要实现KVO则必须实现NSKeyValueObServing 协议,不过 NSObject 已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。
E、KVO在 ObjC 中的用法
1. 注册观察者:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
2. 实现回调监听方法:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
3. 移除观察者:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
F、苹果官方对于KVO的解释及本人翻译
Key-Value Observing Implementation Details
翻译: KVO 实现详解
Automatic key-value observing is implemented using a technique called isa-swizzling.
翻译: KVO 是通过使用 isa-swizzling 技术实现的。
The isa pointer, as the name suggests, points to the object's class which maintains a dispatch table. This dispatch table essentially contains pointers to the methods the class implements, among other data.
翻译: 这个 isa 指针,顾名思义,指向该对象的类,这个类包含了一个派遣信息表。这个派遣信息表本质上包含很多指针,这些指针指向了该类实现的所有方法。
When an observer is registered for an attribute of an object the isa pointer of the observed object is modified, pointing to an intermediate class rather than at the true class. As a result the value of the isa pointer does not necessarily reflect the actual class of the instance.
翻译: 当一个对象的属性被注册了观察者时,指向被观察对象的 isa 指针就被修改了,修改为指向了一个中间类而不是原来的类。其结果是,该 isa 指针不一定反映的就是该实例(被观察者对象)的真实类。
You should never rely on the isa pointer to determine class membership. Instead, you should use the class method to determine the class of an object instance.
翻译: 你永远都不要依赖 isa 指针去确定类成员,你应该使用类方法来确定类的实例对象。
G、KVO 的底层实现:
1. KVO 的底层实现是通过Objective-C强大的运行时(runtime)实现的。
2. 当你第一次观察一个对象object时,runtime 会动态地创建一个继承自该对象object所属类的子类,类名格式为为NSKVONotifying_[subclass名],同时保存注册观察者方法中的所有参数,包括监听者、路径、枚举、携带参数等。
3. 这个新创建的子类重写了所有被观察属性的 setter 方法,并且在内部给观察者发送通知,通知所有观察对象值的更改。
4. 最后把这个对象object的 isa 指针 ( isa 指针告诉 Runtime 系统这个对象的类是什么类型的 ) 指向这个新创建的子类,此时这个被观察的对象 object 就神奇地变成了新的子类的实例。
H、Demo验证:
@interface People : NSObject
@property (nonatomic,strong) NSString *name;
@end
#import "ViewController.h"
#import "People.h"
@interface ViewController ()
@property (nonatomic,strong) People *p;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
People *person = [[People alloc] init];
person.name = @"花无缺";
self.p = person;
// 添加观察者
[person addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];
person.name = @"小鱼儿";
}
// 实现监听方法
-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context{
NSLog(@"%@",change);
}
// 移除监听者
-(void)dealloc{
[self.p removeObserver:self forKeyPath:@"name"];
}
@end