KVO是什么
在iOS开发的过程中,iOS应用通常会把应用程序组建分开成数据模型组件和视图组件
其中数据模型组件负责维护应用程序的状态数据
而视图组件则负责显示数据模型组件内部的状态数据
KVO的来由
对于上面介绍的设计结构,如果程序存在的需求是:
在数据模型组件的状态数据发生改变的时候,
希望视图组件能动态的更新自己,及时的显示数据模型更新后的数据。
- 为此,iOS提供了利用KVO(Key Value Observing,键值监听)机制,NSObject的子类(所有的Oc类都是NSObject的子类)都可以使用该协议中的方法
- KVO机制由
NSKeyValueObserving
协议提供支持 ,该协议包含了一下常用方法用于住注册监听器 -
addObserver:forlKeyPath:options:context
::注册-个监听器用于监听指定的key 路径。
-
removeObserver:forkeyPath:
:为key路径删除指定的监听器
-
removeObserver:forKeyPathicontext
:为key 路径删除指定的监听器。只是多了—个 context
参数。
- 对于上面的需求,很容易想到可以让视区组件来监听数据模型组件的改变,当数据模型组件的key 路径对应的属性值发生改变时,作为监听器的视图组件将会被激发,激发时就会回调监听器自身的监听方法。该监听方法如下:
observeValueForKeyPath:ofObject:change:context
由此可见,作为监听器的视图组件需要重写observeValue ForkeyPath:ofObject:change: context
方法,重写该方法时就可以得到最新改的数据,从而使用最新的数据来更新视图组件的显示
- 从上面的介绍不难看出,KVO 编程的生骤非常简单
-
- ①为被监听对象(通常是数据模型组件》注朋监听器
-
- ②重写监听器的
observe ValueForKeyPath:ofObject:change:context:
方法
- ②重写监听器的
KVO实例
- 和以前一样,创建一个Dog类
#import <Foundation/Foundation.h>
NS_ASSUME_NONNULL_BEGIN
@interface Dog : NSObject
@property (nonatomic, assign) int high;
@end
NS_ASSUME_NONNULL_END
- 我们在视图里面实现一下改变,然后打印改变
ViewController.m
#import <UIKit/UIKit.h>
#import "Dog.h"
@interface ViewController : UIViewController
@property (nonatomic, strong) UILabel* label;
@property (nonatomic, strong) UIButton* button;
@property (nonatomic, strong) Dog* lyt;
ViewContrller.h
#import "ViewController.h"
@interface ViewController ()
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.view.backgroundColor = [UIColor whiteColor];
_label = [[UILabel alloc] init];
_label.frame = CGRectMake(100, 300, 200, 50);
_label.font = [UIFont systemFontOfSize:20];
[self.view addSubview:_label];
// 初始化点击button
_button = [UIButton buttonWithType:UIButtonTypeRoundedRect];
[_button setTitle:@"长高" forState:UIControlStateNormal];
[_button addTarget:self action:@selector(pressButton:) forControlEvents:UIControlEventTouchUpInside];
_button.frame = CGRectMake(15, 400, 100, 40);
[self.view addSubview:_button];
// 设置监听
_lyt = [[Dog alloc] init];
[_lyt addObserver:self forKeyPath:@"high" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionNew context:nil];
}
// 点击button触发监听
- (void)pressButton: (UIButton*)button {
static int high = 0;
_lyt.high = high++;
}
// 监听方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
NSString* str = [NSString stringWithFormat:@"我的身高%d", _lyt.high];
_label.text = str;
NSLog(@" new high %@", [change valueForKey:@"new"]);
}
// 移除监听
- (void)dealloc {
[_lyt removeObserver:self forKeyPath:@"high"];
}
@end
监听效果展示
-
点击一下button 我们设置的监听事件就触发一次
-
记得最后加上取消监听函数(在不使用的时候移除监听)
// 移除监听
- (void)dealloc {
[_lyt removeObserver:self forKeyPath:@"high"];
}