您的位置:首页 > 移动开发 > Objective-C

Objective-C 之 KVO 详解

2015-12-13 20:43 519 查看
A、概要

iOS 开发有多种设计模式,其中就有一种叫做观察者模式,它是通过 KVO 实现的。

B、KVO 简介

KVO 的全称是 Key-Value Observing,是ObjC中原生支持的一种机制。

C、KVO 实现原理

当对一个对象添加观察者,被观察对象的属性值发生变化时,观察者会得到通知,并对变化做出相应的处理。

D、KVO 的特点

1. 支持多个观察者观察同一属性,也支持一个观察者监听不同属性。

2. 利用它可以很容易地实现视图和数据模型的分离,当数据模型的属性值改变之后,作为监听器的视图就会被激发,并回调监听器自身的监听方法。

3. 对于KVC的基本的方法都定义在 NSKeyValueCoding 的非正式协议中,并且NSObject默认实现了该协议。相对的,在ObjC中要实现KVO则必须实现

NSKeyValueObServing 协议,不过 NSObject 已经实现了该协议,因此几乎所有的ObjC对象都可以使用KVO。

E、在 ObjC 中 KVO 的用法

注册观察者:

- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

实现回调监听方法:

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

移除观察者:

- (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验证:

<span style="font-size:12px;">@interface People : NSObject
@property (nonatomic,strong) NSString *name;
@end</span>
<span style="font-size:12px;">#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</span>


添加观察者对象前,isa指向的是原来的类People



当第一次添加观察者对象之后,isa 指针指向了新的类,NSKVONotifying_People

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息