• IOS Key-Value Observing (KVO)


      kvo,与观察者模式类似,通过给指定的对象设置观察者,来检测对象的变化,当指定的对象的属性被修改后,用于作为观察者的对象会接收到通知。简单的说就是每次指定的被观察的对象的属性被修改后,kvo就会自动通知相应的观察者。系统框架已经支持kvo,所以在开发过程中可以直接使用,非常方便。

    一、kvo的使用步骤

    1、注册,指定被观察者的属性

    2、实现回调方法

    3、移除观察

    二、通过现实中的小例子介绍一下kvo的用法

      我有一张银行卡,只要卡内的金额发生的改变,银行就会发短信给我提示,下面通过代码使用kvo来模拟一下这个过程

      先创建一个Card银行卡类,卡里有money金额的属性,在初始化这张卡的时候,给卡里金额设置一个初值1000,然后每隔1秒钟模拟消费10元,代码如下:

      Card.h

    //  Card.h
    //  KVO
    //
    //  Created by jerei on 15-6-5.
    //  Copyright (c) 2015年 jerehedu. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @interface Card : NSObject
    
    @property (nonatomic, assign) float money;
    
    @end

      Card.m

    //  Card.m
    //  KVO
    //
    //  Created by jerei on 15-6-5.
    //  Copyright (c) 2015年 jerehedu. All rights reserved.
    //
    
    #import "Card.h"
    
    @implementation Card
    
    -(instancetype)init
    {
        if (self = [super init]) {
            _money = 1000.0;
            
            [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeMoney) userInfo:nil repeats:YES];
        }
        return self;
    }
    
    //改变卡内金额
    -(void)changeMoney
    {
        self.money -= 10;    
    }
    
    @end

      再创建一个People人类,在这个类中有姓名name和card银行卡两个属性。

      People.h

    //  People.h
    //  KVO
    //
    //  Created by jerei on 15-6-5.
    //  Copyright (c) 2015年 jerehedu. All rights reserved.
    //
    
    #import <Foundation/Foundation.h>
    
    @class Card;
    
    @interface People : NSObject
    
    @property (nonatomic, copy) NSString *name;
    @property (nonatomic, strong) Card *card;
    
    -(id)initWithName:(NSString *)name andCard:(Card *)card;
    
    @end

      People.m

    //  People.m
    //  KVO
    //
    //  Created by jerei on 15-6-5.
    //  Copyright (c) 2015年 jerehedu. All rights reserved.
    //
    
    #import "People.h"
    #import "Card.h"
    
    @implementation People
    
    -(id)initWithName:(NSString *)name andCard:(Card *)card
    {
        if (self = [super init]) {
            _name = name;
            _card = card;
        }
        
        return self;
    }
    
    @end

      创建好了两个类之后,在People类中通过kvo来监测银行卡中金额的变化

    1、人需要监听银行账户中的金额,需要注册监听对象

    - (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(void *)context;

      调用方法的是被监听的对象,参数分别为:

    addObserver:观察者

    forKeyPath:被监听的对象的属性,属性里面还有属性的,可以用点语法

    options:想监听的对象是什么操作,比如初始化、有新的值

    context:上下文,一般为nil,当KeyPath:相同时,可以用它来区分

      因此,在People.m中需要添加的代码为:

    -(id)initWithName:(NSString *)name andCard:(Card *)card
    {
        if (self = [super init]) {
            _name = name;
            _card = card;
       
            //注册,添加观察者
            [_card addObserver:self forKeyPath:@"money" options:NSKeyValueObservingOptionNew|NSKeyValueObservingOptionOld context:nil];
        }
        
        return self;
    }

    2、一旦注册了,就可以去回调函数中感知变化过程

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context;

    observeValueForKeyPath:字符串,被监听的属性

    ofObject:哪一个对象被监听

    change:字典,包含了变化前和变化后的值

    context:上下文

      因此,在People.m中需要实现回调方法

    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        NSLog(@"回调方法 %@",change);
    }

    3、解除监听对象

    - (void)removeObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath;

      调用方法的是被监听的对象

    removeObserver:观察者

    forKeyPath:字符串

      因此,在People.m中重写dealloc方法,实现移除监听者

    -(void)dealloc
    {
        [_card removeObserver:self forKeyPath:@"money"];
    }

    4、ps: kvo属性值改变时,不能直接改值

      例子中Card类中有一个changeMoney方法,在这个方法中修改了被监听属性的值,下面介绍4中方法给大家。

    -(void)changeMoney
    {
        //不能直接改值!!!!
        _money -= 10; //错误的
        
        //1.点语法
        self.money -= 10;
        
        //2. set方法
        float f = _money-10;
        [self setMoney:f];
        
        //3. kvc
        [self setValue:@(f) forKey:@"money"];
        
        //4.
        [self willChangeValueForKey:@"money"];
        _money -= 10;
        [self didChangeValueForKey:@"money"];
        
    }

      如有疑问咨询或技术交流,请加入官方QQ群:JRedu技术交流 (452379712)

    作者:杰瑞教育
    出处:http://www.cnblogs.com/jerehedu/ 
    本文版权归烟台杰瑞教育科技有限公司和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。
     
  • 相关阅读:
    检测c/c++中内存泄露
    在一个集合S中寻找最大的C使A+B=C且A,B,C均在集合当中
    《为学》
    U盘windows无法格式化的解决办法
    java.lang.AbstractMethodError: oracle.jdbc.driver...解决方法
    sqlplus连接远程Oracle
    oracle字符集导致的乱码问题
    大端与小端存储模式详解
    《劝学》原文
    《报任安书》司马迁
  • 原文地址:https://www.cnblogs.com/jerehedu/p/4580088.html
Copyright © 2020-2023  润新知