IOS 的 KVO机制
概述
Key-Value Observing (简写为KVO):当指定的对象的属性被修改了,允许对象接受到通知的机制。每次指定的被观察对象的属性被修改的时候,KVO都会自动的去通知相应的观察者。
KVO优点
当有属性改变,KVO会提供自动的消息通知。这样的架构有很多好处。首先,开发人员不需要自己去实现这样的方案:每次属性改变了就发送消息通知。这是KVO 机制提供的最大的优点。因为这个方案已经被明确定义,获得框架级支持,可以方便地采用。开发人员不需要添加任何代码,不需要设计自己的观察者模型,直接可 以在工程里使用。其次,KVO的架构非常的强大,可以很容易的支持多个观察者观察同一个属性,以及相关的值。
实例
假设一个场景,电影票的价格显示在当前屏幕上,当电影票价格更改的时候,实时显示更新其价格
1、定义DataModel
#import <Foundation/Foundation.h>
@interface MovieTicket : NSObject
@property (nonatomic, strong) NSString *title;
@property (nonatomic, assign) float price;
@end
#import "MovieTicket.h"
@implementation MovieTicket
@end
2、viewControl界面
3、viewControl代码
#import "ViewController.h"
#import "MovieTicket.h"
NSString *const kChange = @"change";
@interface ViewController ()
@property (weak, nonatomic) IBOutlet UILabel *titleLab;
@property (weak, nonatomic) IBOutlet UILabel *priceLab;
@property (nonatomic, strong) MovieTicket *ticket;
@end
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
MovieTicket *ticket = [[MovieTicket alloc] init];
ticket.title = @"钢铁侠";
ticket.price = 1.99;
self.titleLab.text = ticket.title;
self.priceLab.text = [NSString stringWithFormat:@"%f", ticket.price];
// 1、 注册,制定被观察者的属性,被观察者是 ticket,观察者是当前控制器
// 注意: 对象之间建立连接,而不是两个类之间
[ticket addObserver:self forKeyPath:kChange options:0 context:NULL];
// 单独观察 ticket 的 price 属性,不需要实现 willChangeValueForKey: 和 didChangeValueForKey:方法
//[ticket addObserver:self forKeyPath:@"price" options:0 context:NULL];
self.ticket = ticket;
}
- (void)dealloc {
// 3、移除观察
[self.ticket removeObserver:self forKeyPath:kChange];
}
// 点击 "改变票价" 模拟 改变属性
- (IBAction)changePriceBtnClick:(id)sender {
// 将改变属性的代码写在 willChangeValueForKey: 和 didChangeValueForKey: 之间
[self.ticket willChangeValueForKey:kChange];
self.ticket.title = @"美国队长";
self.ticket.price = arc4random();
[self.ticket didChangeValueForKey:kChange];
}
// 2、在观察者中实现回调方法,当被观察者的监听的属性发生改变时调用
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary<NSString *,id> *)change
context:(void *)context {
if ([keyPath isEqualToString:kChange]) {
self.titleLab.text = self.ticket.title;
self.priceLab.text = [NSString stringWithFormat:@"%f", self.ticket.price];
}
if ([keyPath isEqualToString:@"price"]) {
}
}
@end