iOS KVO使用介绍

235 阅读3分钟

这是我参与11月更文挑战的第16天,活动详情查看:2021最后一次更文挑战

前言

本章简单介绍下什么是KVO,如何使用KVO~

什么是KVO

KVO 是:key-value observiing 键值监听,就是可以监听键值的改变,用来监听某个对象的属性值的改变

如何使用 KVO

使用步骤:

  1. 确定要监听的目标
  2. 设置监听
  3. 设置监听回调
  4. 移除监听

1.确定监听目标

就是要确定到底要监听哪个对象的哪个属性

比如有个persion对象,对象中有个address属性,你想监听到这个对象的address属性的改变

@interface ViewController ()
@property (nonatomic, strong) Persion * persion;
@end

2.设置监听

设置监听可以使用- (**void**)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(**nullable** **void** *)context;这个方法。

这个方法有四个参数:

  • observer :监听者是谁,也就是当发生改变时通知谁,调用她的- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context方法,一般我们写self
  • keyPath :key的路径,也就是要监听的属性名称,这里就是address
  • options : 监听选项,具体监听那些状态,一般都写NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld,这样就会监听到值的改变
  • context: 上下文,在通知监听者时携带的上下文信息,会将这个上下文传递给监听者,也就是- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context方法中的context,一般可以写nil

options 参数的全部可选值介绍:

NSKeyValueObservingOptionNew :提供属性的新值

NSKeyValueObservingOptionOld :提供属性的旧值

NSKeyValueObservingOptionInitial:设置后,在添加监听者的时候回立即通知给监听者

NSKeyValueObservingOptionPrior:设置后,每次修改属性的值时,会在值改变前,先通知一下监听者,然后改变后再通知一次

比如我们要监听persion对象的address属性可以这样写:

//设置监听
    [self.persion addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"我地址变了,来找我玩呀~"];

3.设置监听回调

监听者需要实现监听回调,方便在监听到属性值改变时通知到监听者发生了改变

监听者需要实现- (**void**)observeValueForKeyPath:(NSString *)keyPath ofObject:(**id**)object change:(NSDictionary<NSKeyValueChangeKey,**id**> *)change context:(**void** *)context

这个方法有几个值传递进来:

  • keyPath:发生改变的属性路径,这里就是address
  • object:被监听的对象,这里就是self.persion
  • change:发生改变具体的信息,里面有改变的具体值信息
  • context: 上下文

上面的例子可以这样写:

//设置监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"收到监听 %@的%@改变了,具体信息:%@ 上下文:%@",object,keyPath,change,context);
}

例子只是做了个打印

4.移除监听

在不用的时候要及时移除监听,移除监听的方法有两个:

- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath context:(nullable void *)context API_AVAILABLE(macos(10.7), ios(5.0), watchos(2.0), tvos(9.0));
- (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;
  • observer: 监听者,就是设置监听时传递的observer,一般是self

  • keyPath: 监听的属性名称,这里是address

  • context : 这个方法需要传递上下文信息,这个上下文信息就是添加监听时传递的上下文信息。

上面例子的移除监听可以这样写:

//移除监听
    [self.persion removeObserver:self forKeyPath:@"address" context:@"我地址变了,来找我玩呀~"];

整个例子完整代码:

#import "ViewController.h"
#import "Persion.h"

@interface ViewController ()
@property (nonatomic, strong) Persion * persion;
@end

@implementation ViewController

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.view.backgroundColor = UIColor.whiteColor;
    
    self.persion = [Persion new];
    self.persion.address = @"001 room";
    
    //设置监听
    [self.persion addObserver:self forKeyPath:@"address" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:@"我地址变了,来找我玩呀~"];
    
}

- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
    //改变属性的值
    self.persion.address = @"003 room";
}

//设置监听回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    NSLog(@"收到监听 %@的%@改变了,具体信息:%@ 上下文:%@",object,keyPath,change,context);
}

- (void)dealloc {
    //移除监听
    [self.persion removeObserver:self forKeyPath:@"address" context:@"我地址变了,来找我玩呀~"];
}

@end

打印结果:

收到监听 <Persion: 0x7fd816409650>的address改变了,具体信息:{
    kind = 1;
    new = "003 room";
    old = "001 room";
} 上下文:我地址变了,来找我玩呀~

KVO原理