OC KVO模式

2019-08-19  本文已影响0人  的的可可

简介

KVO是Key-Value Observing的简称,也就是键值观察。和广播通知一样,是ios中的一种通知机制,允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。

KVO和NSNotificationCenter都是iOS中观察者模式的一种实现。区别在于,相对于被观察者和观察者之间的关系,KVO是一对一的,而不一对多的。KVO对被监听对象无侵入性,不需要修改其内部代码即可实现监听。

这是一张图片

乔布斯同学,成绩不好没及格,但是他计算机很牛逼,学校为了防止他入侵系统修改分数,设置了一个报警系统--分数被修改就发出通知。当然实现这个需求的方法很多,这次就用kvo试试。

首先设置一个Model里面放上name和score

#import <Foundation/Foundation.h>

@interface StudentModel : NSObject

@property (nonatomic, copy) NSString *name;
@property float score;

@end

然后就是搞UI和添加观察者

#import "ViewController.h"
#import "StudentModel.h"

//设备的宽高
#define SCREENWIDTH       [UIScreen mainScreen].bounds.size.width
#define SCREENHEIGHT      [UIScreen mainScreen].bounds.size.height

@interface ViewController ()

@property (nonatomic, strong) StudentModel *studentModel;
@property (nonatomic, strong) UILabel *scoreLabel;

@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    self.view.backgroundColor = [UIColor darkGrayColor];
    
    // 实例化并设置监听
    self.studentModel = [[StudentModel alloc] init];
    [self.studentModel setValue:@"乔布斯" forKey:@"name"];
    [self.studentModel setValue:@"59.0" forKey:@"score"];
    //创建观察者
/***
*  self.studentModel:被观察的对象
*  self:观察者
*  score:被观察的键
*  options:一个枚举,后面详细介绍
*  context:这里可以传值
***/
    [self.studentModel addObserver:self forKeyPath:@"score" options:NSKeyValueObservingOptionNew |  NSKeyValueObservingOptionOld context:@"分数被改变了"];
    
    // 界面内容
    // 名字
    UILabel *nameLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 200, SCREENWIDTH, 20)];
    nameLabel.text = [NSString stringWithFormat:@"Name:%@", [self.studentModel valueForKey:@"name"]];
    nameLabel.textColor = [UIColor whiteColor];
    nameLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:nameLabel];
    
    // 分数
    self.scoreLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 250, SCREENWIDTH, 20)];
    self.scoreLabel.text = [NSString stringWithFormat:@"Score:%@", [self.studentModel valueForKey:@"score"]];
    self.scoreLabel.textColor = [UIColor whiteColor];
    self.scoreLabel.textAlignment = NSTextAlignmentCenter;
    [self.view addSubview:self.scoreLabel];
    
    // 按钮
    UIButton *btn = [[UIButton alloc] initWithFrame:CGRectMake((SCREENWIDTH - 100)/2, 300, 100, 20)];
    [btn setTitle:@"修改分数" forState:UIControlStateNormal];
    [btn addTarget:self action:@selector(changeScore) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:btn];
    
//    [self.studentModel removeObserver:self forKeyPath:@"score"];// 4.移除观察者
}

// 按钮响应
- (void)changeScore {
    [self.studentModel setValue:@"99.0" forKey:@"score"];
}

这里我们就需要kvo干事情了

// KVO回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"score"]) {
        self.scoreLabel.text = [NSString stringWithFormat:@"Score:%@", [self.studentModel valueForKey:@"score"]];
    }
    NSLog(@"keyPath:%@",keyPath);//被观察的键
    NSLog(@"object:%@",object);//被观察者
    NSLog(@"context:%@", context);// 通过context获取被观察者传递的内容
    NSLog(@"change:%@", change);// 根据change的设置获取新值、旧值等
    NSLog(@"新值:%@",change[@"new"]);
    NSLog(@"旧值:%@",change[@"old"]);
    
}

点击按钮后的输出结果为:

2019-08-19 15:31:02.868719+0800 KVODemo[2660:437306] keyPath:score
2019-08-19 15:31:02.868838+0800 KVODemo[2660:437306] object:<StudentModel: 0x600001bc3340>
2019-08-19 15:31:02.868918+0800 KVODemo[2660:437306] context:分数被改变了
2019-08-19 15:31:02.869062+0800 KVODemo[2660:437306] change:{
    kind = 1;
    new = 99;
    old = 59;
}
2019-08-19 15:31:02.869130+0800 KVODemo[2660:437306] 新值:99
2019-08-19 15:31:02.869217+0800 KVODemo[2660:437306] 旧值:59

然后在适当的时候移除观察者

[self.studentModel removeObserver:self forKeyPath:@"score"]

options参数

在添加观察者时有一个options参数,在回调获取变化时有一个change参数,这两个参数其实是对应的,都是用来增加传递变化的丰富度。

options参数可以设为:

change参数

在使用change的时候可以通过下面的key来操作:

上一篇下一篇

猜你喜欢

热点阅读