zoukankan      html  css  js  c++  java
  • KVO的使用

    技术概述

    KVO全称KeyValueObserving,是苹果提供的一套事件通知机制。允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。

    技术详述

    基础使用

    1. 通过addObserver:forKeyPath:options:context:方法注册观察者,观察者可以接收keyPath属性的变化事件。
      在观察者中实现

    2. observeValueForKeyPath:ofObject:change:context:方法,当keyPath属性发生改变后,KVO会回调这个方法来通知观察者。

    3. 当观察者不需要监听时,可以调用removeObserver:forKeyPath:方法将KVO移除。需要注意的是,调用removeObserver需要在观察者消失之前,否则会导致Crash。

    注册方法

    在注册观察者时,可以传入options参数,参数是一个枚举类型。如果传入NSKeyValueObservingOptionNew和NSKeyValueObservingOptionOld表示接收新值和旧值,默认为只接收新值。如果想在注册观察者后,立即接收一次回调,则可以加入NSKeyValueObservingOptionInitial枚举。

    还可以通过方法context传入任意类型的对象,在接收消息回调的代码中可以接收到这个对象,是KVO中的一种传值方式。

    在调用addObserver方法后,KVO并不会对观察者进行强引用,所以需要注意观察者的生命周期,否则会导致观察者被释放带来的Crash。

    监听方法

    观察者需要实现observeValueForKeyPath:ofObject:change:context:方法,当KVO事件到来时会调用这个方法,如果没有实现会导致Crash。change字典中存放KVO属性相关的值,根据options时传入的枚举来返回。枚举会对应相应key来从字典中取出值,例如有NSKeyValueChangeOldKey字段,存储改变之前的旧值。

    change中还有NSKeyValueChangeKindKey字段,和NSKeyValueChangeOldKey是平级的关系,来提供本次更改的信息,对应NSKeyValueChange枚举类型的value。例如被观察属性发生改变时,字段为NSKeyValueChangeSetting。

    如果被观察对象是集合对象,在NSKeyValueChangeKindKey字段中会包含NSKeyValueChangeInsertion、NSKeyValueChangeRemoval、NSKeyValueChangeReplacement的信息,表示集合对象的操作方式。

    实际应用

    KVO主要用来做键值观察操作,想要一个值发生改变后通知另一个对象,则用KVO实现最为合适。

    #import <Foundation/Foundation.h>
     
    @interface Book : NSObject
     
    @property (nonatomic,strong)NSString *name;
    @property (nonatomic,strong)NSString *price;
     
    @end
    
    #import "ViewController.h"
    #import "Book.h"
     
    @interface ViewController ()
     
    @property (nonatomic,strong)Book *abook;
     
    @end
     
    @implementation ViewController
     
    - (void)viewDidLoad {
        [super viewDidLoad];
        
        [self addObserver];
        [self addBtn];
     
    }
     
     
    /**
     添加监听
     */
    -(void)addObserver{
        
        //添加监听
        self.abook = [[Book alloc]init];
        self.abook.price = @"0";//先设一个初始值
        [_abook addObserver:self forKeyPath:@"price" options:NSKeyValueObservingOptionOld|NSKeyValueObservingOptionNew context:nil];
        
    }
     
     
    /**
     添加一个按钮
     */
    -(void)addBtn{
        
        UIButton *abtn = [UIButton buttonWithType:UIButtonTypeCustom];
        abtn.frame = CGRectMake(80, 90.0, 80, 30);
        [abtn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
        [abtn setTitle:@"Change" forState:UIControlStateNormal];
        [abtn addTarget:self action:@selector(btnClick) forControlEvents:UIControlEventTouchUpInside];
        [self.view addSubview:abtn];
        
    }
     
     
    /**
     按钮点击事件
     */
    -(void)btnClick{
        
        NSLog(@"点击了Btn!");
        NSInteger randomPrice = arc4random() % 100;
        NSString *newPrice = [NSString stringWithFormat:@"%ld",(long)randomPrice];
        
        //触发监听
        //第一种方法
    //    NSDictionary *newBookPropertiesDictionary=[NSDictionary dictionaryWithObjectsAndKeys:
    //                                               @"book name",@"name",
    //                                               newPrice,@"price",nil];
    //    [self.abook setValuesForKeysWithDictionary:newBookPropertiesDictionary];
        
        //第二种方法
        [self.abook setValue:newPrice forKey:@"price"];
     
      不仅可以通过点语法和set语法进行调用,KVO兼容很多种调用方式。
     
     
    }
     
    //实现监听
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        if ([keyPath isEqual:@"price"]) {
            NSLog(@"old price: %@",[change objectForKey:@"old"]);
            NSLog(@"new price: %@",[change objectForKey:@"new"]);
        }
    }
     
    -(void)dealloc
    {
        //移除监听
        [_abook removeObserver:self forKeyPath:@"price"];
    }
     
     
    @end
    

    打印结果

    KVOTest[40935:3327447] 点击了Btn!
    KVOTest[40935:3327447] old price: 0
    KVOTest[40935:3327447] new price: 87
    KVOTest[40935:3327447] 点击了Btn!
    KVOTest[40935:3327447] old price: 87
    KVOTest[40935:3327447] new price: 49
    

    总结

    1. KVO在使用时添加观察者和移除观察者应到成对出现
    2. 被观察者在销毁前应当移除所有的观察者,iOS10以下会崩溃,iOS11以上不会崩溃,坑点!
    3. 一个对象如果作为观察者,在该对象dealloc前应当被移除,否则会导致崩溃

    参考文献

    KVO的使用及底层实现

  • 相关阅读:
    C#跨窗体操作(引用传递)
    C#中使用自定义消息
    WebService基于SoapHeader实现安全认证[webservice][.net][安全][soapheader]
    C#webBrowser实现在新选项卡打开链接
    ASP.NET FormsAuthentication跨站点登录时绝对地址返回的问题
    winform 实现TextBox 关键字智能提示
    SQL批量上传海量数据的存储过程
    优化SQL 语句 in 和not in 的替代方案
    (转)CMMI+人性化管理=软件流程改善成功之道
    两个ComboBox互相联动的一种解决方法
  • 原文地址:https://www.cnblogs.com/MingLL/p/13183294.html
Copyright © 2011-2022 走看看