• KVO详解


    键值观察(KVO)是基于键值编码的一种技术。

    利用键值观察可以注册成为一个对象的观察者,在该对象的某个属性变化时收到通知。

    被观察对象需要编写符合KVC标准的存取方法,编写键值观察分为以下三步:

    (1)注册成为观察者。

    (2)定义KVO的回调。

    (3)移除观察者。

    +新建一个类Student,属性为name,age。

    @interface Student : NSObject
    @property(copy,nonatomic) NSString * name;
    @property(nonatomic) int age;
    @end

    新建一个Parent类,作为观察者。main函数:

    复制代码
        Student * student = [Student new];
        Parent * parent = [Parent new];
        //建立观察者模式关系,注册观察者
        [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];     
        [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];
    复制代码

    第一个参数:(student)被观察者。

    第二个参数:(parent)观察者。

    第三个参数:(forKeyPath)键路径参数,要观察的键路径,这里观察name和age。

    第四个参数:(options)标识KVO希望变化如何传递给观察者,可以使用|进行多选,这里观察变化的新值和旧值。

    第五个参数:上下文内存区,通常为nil

    +在parent.m的文件中定义KVO的回调。

    复制代码
    @implementation Parent
    //观察者实现键值观察方法,要作为观察者,需要实现这个方法。
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
        id newValue = [change objectForKey:NSKeyValueChangeNewKey];
        NSLog(@"家长观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
    }
    复制代码

    其中change是一个字典。

    +如果student的name或age发生变化(最后要移除观察者):

    复制代码
        Student * student = [Student new];
        Parent * parent = [Parent new];
        //建立观察者模式关系,注册观察者
        [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];
        [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];
        student.age = 10;
        student.name = @"小明";
        //结束之前需要移除观察者
        [student removeObserver:parent forKeyPath:@"age"];
        [student removeObserver:parent forKeyPath:@"name"];
    复制代码

    那么parent上定义的的回调会自动执行,打印结果:

    当然也可以多个对象观察一个对象,新建teacher类,这样就有两个观察者:

    复制代码
        Student * student = [Student new];
        Parent * parent = [Parent new];
        Teacher * teacher = [Teacher new];
        //建立观察者模式关系,注册观察者
        [student addObserver:parent forKeyPath:@"name" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];
         [student addObserver:teacher forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld context:nil];
            
         [student addObserver:parent forKeyPath:@"age" options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld
                         context:nil];
         student.age = 10;
         student.name = @"小明";
         //结束之前需要移除观察者
         [student removeObserver:parent forKeyPath:@"age"];
         [student removeObserver:parent forKeyPath:@"name"];
         [student removeObserver:teacher forKeyPath:@"age"];
    复制代码

    ****************************************

    另外一种情况:新建Family类,让student成为它的一个属性,然后让Family成为student的观察者,这样注册观察者的方法可以写在Family的init方法中,移除观察者写在Family的dealloc方法中:

    Family.h文件:

    @interface Family : NSObject
    @property(strong,nonatomic) Student * student;
    -(id) initWithStudent:(Student *)student;
    @end

    Family.m文件:

    复制代码
    @implementation Family
    -(id)initWithStudent:(Student *)student
    {
        if(self = [super init]){
            self->_student = student;
            //让当前对象成为student的观察者
            [self->_student addObserver:self forKeyPath:@"name" options:NSKeyValueObservingOptionNew |NSKeyValueObservingOptionOld  context:nil];
        }
        return self;
    }
    
    //观察者实现键值观察方法,要作为观察者,需要实现这个方法。
    -(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
    {
        
        id oldValue = [change objectForKey:NSKeyValueChangeOldKey];
        id newValue = [change objectForKey:NSKeyValueChangeNewKey];
        NSLog(@"家庭观察对象:对象:%@的属性%@的值发生了改变,旧值为:%@,新值为:%@",object,keyPath,oldValue,newValue);
    }
    
    -(void)dealloc
    {
        NSLog(@"Family dealloc...");         
        //移除观察者
        [self->_student removeObserver:self forKeyPath:@"name"];   //ARC所以不用写super dealloc
    }
    @end
    复制代码

    main:

        Student * student = [Student new];
        Family * family = [[Family alloc]initWithStudent:student];
        student.name = @"hehe";
  • 相关阅读:
    【LSA推荐算法】简单理解
    【数据分析案例】用户消费行为
    【Django】rest_framework 序列化自定义替换返回值
    【Django+Element UI】使用一个接口文件,搞定分页获取数据,模糊查询后分页获取数据
    【Django后端分离】使用element-ui文件上传
    JavaScript数组去重方法总结
    MySQL索引优化--对前缀索引使用like模糊匹配时的实际索引选择
    Linux命令--top
    Linux命令--free
    MySQL中的表的列设置为varchar(0)或char(0)
  • 原文地址:https://www.cnblogs.com/liuyingjie/p/4949100.html
Copyright © 2020-2023  润新知