1、KVO的简介
KVO 全称 Key-Value Observing。中文叫键值观察。KVO其实是一种观察者模式,观察者在键值改变时会得到通知,利用它可以很容易实现视图组件和数据模型的分离,当数据模型的属性值改变之后作为监听器的视图组件就会被激发,激发时就会回调监听器自身。相比Notification,KVO更加的简单直接。
KVO的操作方法由NSKeyValueCoding提供,而他是NSObject的类别,也就是说ObjC中几乎所有的对象都支持KVO操作。
KVO 需要实现实例变量的 setter/getter方法
2、KVO的实现
0) KVO的使用也很简单,就是简单的3步。
(1)注册需要观察的对象的属性addObserver:forKeyPath:options:context:
(2)实现observeValueForKeyPath:ofObject:change:context:方法,这个方法当观察的属性变化时会自动调用.在这个方法中还通过 NSKeyValueObservingOptionNew这个参数要求把新值在dictionary中传递过来。
(3)取消注册观察removeObserver:forKeyPath:context:
1)注册
实现方法:
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;
方法参数:
object : 被观察对象
observer: 观察对象
forKeyPath里面带上property的name,如UIView的frame、center等等
options: 有4个值,分别是:
NSKeyValueObservingOptionNew 把更改之前的值提供给处理方法
NSKeyValueObservingOptionOld 把更改之后的值提供给处理方法
NSKeyValueObservingOptionInitial 把初始化的值提供给处理方法,一旦注册,立马就会调用一次。通常它会带有新值,而不会带有旧值。
NSKeyValueObservingOptionPrior 分2次调用。在值改变之前和值改变之后。
注:例子里的0就代表不带任何参数进去
context: 可以带入一些参数,其实这个挺好用的,任何类型都可以,自己强转就好了。
2)监测
实现方法:
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary<NSString*, id> *)change context:(nullable void *)context;
这个方法当观察的属性变化时会自动调用.在这个方法中还通过NSKeyValueObservingOptionNew这个参数要求把新值在dictionary中传递过来。
方法参数:
keyPath: 对应forKeyPath
object: 被观察的对象
change: 对应options里的NSKeyValueObservingOptionNew、NSKeyValueObservingOptionOld等
context: 对应context
3)取消注册观察
实现方法:
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context NS_AVAILABLE(10_7, 5_0);
方法参数:
同上
3、具体实现代码
main.m
1 // 2 // main.m 3 // KVO具体实现 4 // 5 // Created by ma c on 16/5/18. 6 // Copyright © 2016年 彭盛凇. All rights reserved. 7 // 8 9 #import <Foundation/Foundation.h> 10 #import "Person.h" 11 #import "Watch.h" 12 13 int main(int argc, const char * argv[]) { 14 @autoreleasepool { 15 16 Person *person = [[Person alloc] init]; 17 18 Watch *watch = [[Watch alloc] init]; 19 20 person.watch = watch; 21 22 [person registerObserver]; 23 24 person.name = @"pss"; 25 26 person.name = @"pbb"; 27 28 } 29 return 0; 30 }