iOS-KVO简单使用

KVO

  • 概述
    KVO是key-value-observe的简称,键值观察者,是一种设计模式–观察者模式。也就是当被观察者的状态发生改变时,会通知给观察者,观察者在对应的方法里可以获取相关信息。监听对象属性的变化,对属性才会有作用,一般继承自NSobject的对象都默认支持KVO,KVO监听的是属性的set方法,

  • 简单使用

    • 注册观察者
方法:  A addObserver: B forKeyPath: options: context:
参数含义: 
1. A 为被观察者;B(observe):观察者,监听属性变化的对象。该对象必须要实现observe ValueForKeyPath:ofObjec:change:context:方法
2. keyPath: 要观察的属性的名称,要和属性声明的名称一致。
3. options:对KVO机制进行配置,修改KVO通知的时机以及通知的内容,决定提供给观察者change字典中的具体信息有哪些
4. context:传入任意类型的对象,在“接收消息回调”的代码中可以接收到这个对象,可以写为nil
options解析
typedef NS_OPTIONS(NSUInteger, NSKeyValueObservingOptions) {
		表示监听对象的新值,即变化后的值,change字典中会包含该key的键值对,通过该key即new,就可以取到属性变化后的值
        NSKeyValueObservingOptionNew = 0x01,
        
        表示监听对象的新值,即变化前的值,change字典中会包含该key的键值对,通过该key,即old,就可以取到属性变化后的值
        NSKeyValueObservingOptionOld = 0x02,
        
  		在注册观察者的方法return的时候就会发出一次通知,比如:在viewDidLoad方法运行完,通知就发出去了
        NSKeyValueObservingOptionInitial API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 0x04,
        
        会在值改变前发出一次通知,改变后的通知依旧会发出,也就是每次change都会有两个通知
        NSKeyValueObservingOptionPrior API_AVAILABLE(macos(10.5), ios(2.0), watchos(2.0), tvos(9.0)) = 0x08
    };

如下例:为a_Student注册一个观察者,观察它的name属性,提供给change变化后的值和变化前的值

[_aStudent addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];

  • 实现回调
方法:observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context
参数:
keyPath: 所观察对象的属性
object:所观察的对象
change:属性值的变化

change的解析
NSKeyValueChangeKey枚举
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeKindKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNewKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeOldKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeIndexesKey;
FOUNDATION_EXPORT NSKeyValueChangeKey const NSKeyValueChangeNotificationIsPriorKey 

NSKeyValueChange枚举
typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
    NSKeyValueChangeSetting = 1,
    NSKeyValueChangeInsertion = 2,
    NSKeyValueChangeRemoval = 3,
    NSKeyValueChangeReplacement = 4,
};
当change[NSKeyValueChangeKindKey]是NSKeyValueChangeSetting的时候,说明被观察的属性的setter方法被调用了。
inser,remove,replace:被观察者属性是集合类型,且对它进行inser,remove,replace操作的时候会返回这三种Key

如下,当keyPath,即观察者的属性为name时,打印出其变化前后的值

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"old name: %@", [change objectForKey:@"old"]);
        NSLog(@"new name: %@", [change objectForKey:@"new"]);
    }
}

  • 移除观察者
- (void)dealloc {
	//根据对应的观察者的属性进行移除
    [_aStudent removeObserver:self forKeyPath:@"name"];
}
  • 小小的注意
	//初识的值
   _aStudent.name = 12;
   //进行改变时,将值继续赋为12
  _aStudent.name = 12;

此时仍然会发出通知,因为此时执行了set方法,触发了监听,为了避免这一情况,可以手动设置KVO,上面的是自动KVO,也就是,在类中添加属性时是自动生成对应的getter/setter方法的。

  • 具体的例子

    Student是我自己创建的一个类

@interface Student : NSObject

@property (nonatomic, strong) NSString *name;
@property (nonatomic, strong) NSString *age;
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.nameTextField = [[UITextField alloc] init];
    [self.view addSubview:_nameTextField];
   
    _nameTextField.frame = CGRectMake(100, 100, 200, 40);
    _nameTextField.placeholder = @"请输入姓名";
    _nameTextField.layer.borderColor = [UIColor blackColor].CGColor;
    _nameTextField.layer.borderWidth = 1;
    
    _addButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
    [self.view addSubview:_addButton];
    
    _addButton.frame = CGRectMake(100, 160, 80, 40);
    [_addButton setTitle:@"改变" forState:UIControlStateNormal];
    [_addButton addTarget:self action:@selector(clickchange) forControlEvents:UIControlEventTouchUpInside];
    
    _aStudent = [[Student alloc] init];
    _aStudent.name = @"123";//先设初值
    _aStudent.age = @"12";
    [_aStudent addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
    
    
}

-(void)clickchange {
    if (_nameTextField.text) {
        
        //触发
        _aStudent.name = _nameTextField.text;
        
    }
}

//当kvo事件到来时,会调用这个方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    if ([keyPath isEqualToString:@"name"]) {
        NSLog(@"old name: %@", [change objectForKey:@"old"]);
        NSLog(@"new name: %@", [change objectForKey:@"new"]);
    }
}

//移除
- (void)dealloc {
    [_aStudent removeObserver:self forKeyPath:@"name"];
}

通知,代理,KVO的区别

  • 通知NSNotification。通知中心NSNotificationCenter
    使用范围:任何对象之间都可以传递消息,一个对象可以发通知给多个对象,一个对象也可以接收多个对象发出的通知
  • KVO
    仅仅只能监听对象属性的改变,灵活度不太高
  • 代理
    一个对象只能设置一个代理,(假设这个对象只有一个代理属性)
    一个对象能成为多个对象的代理
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值