美文网首页
OC KVO模式

OC KVO模式

作者: 的的可可 | 来源:发表于2019-08-19 15:41 被阅读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参数可以设为:

    • NSKeyValueObservingOptionOld:这表示在回调获取变化时可以通过change参数获取变化之前的值;

    • NSKeyValueObservingOptionNew:这表示在回调获取变化时可以通过change参数获取变化后的值;

    • NSKeyValueObservingOptionInitial:在添加观察者方法return的时候就发出一次通知;

    • NSKeyValueObservingOptionPrior:会在观察的值发生变化前发出一次通知,变化后还是会发出一次通知,所以变化一次一共会得到两次通知。

    change参数

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

    • NSKeyValueChangeKindKey:对应NSKeyValueChange的枚举值
      1: NSKeyValueChangeSetting = 1:说明被观察的数据的setter方法被调用了;

      2:NSKeyValueChangeInsertion = 2:当观察的数据是集合时,且对它进行insert操作时会返回该值;

      3:NSKeyValueChangeRemoval = 3:当观察的数据是集合时,且对它进行remove操作时会返回该值;

      4:NSKeyValueChangeReplacement = 4:当观察的数据是集合时,且对它进行replace操作时会返回该值。

    • NSKeyValueChangeNewKey:对应options参数中的NSKeyValueObservingOptionNew,会在其中包含观察的数据变化后的新值

    • NSKeyValueChangeOldKey:对应options参数中的NSKeyValueObservingOptionOld,会在其中包含观察的数据变化之前得旧值

    • NSKeyValueChangeIndexesKey:当NSKeyValueChangeKindKey是2、3、4的时候,也就是说是观察集合数据时,这个key的值是一个NSIndexSet,包含操作对象的索引集合

    • NSKeyValueChangeNotificationIsPriorKey:包含一个布尔值,如果options的参数是NSKeyValueObservingOptionPrior,也就是会通知两次,在第一次通知,也就是改变前的通知时,会包含这个key

    相关文章

      网友评论

          本文标题:OC KVO模式

          本文链接:https://www.haomeiwen.com/subject/adnssctx.html