iOS --KVO

KVO,即:Key-Value Observing,
它提供一种机制,当指定的对象的属性被修改后,则对象就会接受到通知。简单的说就是每次指定的被观察的对象的属性被修改后,KVO就会自动通知相应的观察者了.
与NSNotification 不同的是。KVO 不需要通知中心对象。而是在对象属性变化之后会直接通知观察者。KVO是基于KVC的。
KVO是一个对象能够观察另外一个对象的属性的值,并且能够发现值的变化。这是一个对象与另外一个对象保持同步的一种方法,即当另外一种对象的状态发生改变时,观察对象马上作出反应。它只能用来对属性作出反应,而不会用来对方法或者动作作出反应。
KVO不能观察对象
实现原理:当为某一个对象属性注册监听的时候,该对象的isa指针就会指向一个中间类,而不是本来对象真实的类。所以说,对象的isa指针可以改变,我们的程序最好不要依赖isa指针。

简而言之就是:
1、当一个object有观察者时,动态创建这个object的类的子类
2、对于每个被观察的property,重写其set方法
3、在重写的set方法中调用- willChangeValueForKey:和- didChangeValueForKey:通知观察者
4、当一个property没有观察者时,删除重写的方法
5、当没有observer观察任何一个property时,删除动态创建的子类
KVO == Key Value Observing
1. KVO的作用:
可以监听某个对象属性的改变
2. KVO的内部实现原理:
KVO是基于runtime机制实现的

当某个类的属性对象第一次被观察时,系统就会在运行期间动态地创建该类的一个派生类,在这个派生类中重写基类的任何被观察属性的setter方法。派生类在被重写的setter方法内实现真正的通知机制

如果原类为Person,那么生成的派生类名为NSKVONotifying_Person
我们知道,每一个类中都有一个isa指针指向当前类,所有系统就是在当一个类的对象第一次被观察的时候,系统就会偷偷将isa指针指向动态生成的派生类,从而在被监听属性赋值时被执行的是派生类的setter方法
键值观察通知依赖于NSObject 的两个方法: willChangeValueForKey: 和 didChangevlueForKey:;在一个被观察属性发生改变之前, willChangeValueForKey: 一定会被调用,这就 会记录旧的值。而当改变发生后,didChangeValueForKey: 会被调用,继而 observeValueForKey:ofObject:change:context: 也会被调用。
补充:KVO的这套实现机制中苹果还偷偷重写了class方法,让我们误认为还是使用的当前类,从而达到隐藏生成的派生类
这里写图片描述
3. 用法:
创建对象,然后设置监听对象属性变化,
然后设置监听变化方法observeValueForKeyPath….监听模型属性发生变化就会调用此方法,
最后要记得从对象上移除监听。
4. 注意:
KVO只能监听通过set方法修改的值
如果使用KVO监听某个对象的属性, 当对象释放之前一定要移除监听
经典错误:reason: ‘An instance 0x7f9483516610 of class Person was deallocated while key value observers were still registered with it.
5. 使用:监听Person的age属性变化
创建被监听的对象:person

    //    KVO == Key Value Observing
            //    作用: 可以监听某个对象属性的改变
                Person *p1 = [Person new];
                p1.name = @"张雨生";
                p1.age = 18;

2.监听person对象的age属性的变化
给p这个对象添加一个监听 , 监听p1对象的age属性的改变, 只要age属性改变就通知self

  /*
      第一个参数: 告诉系统哪个对象监听
      第二个参数: 监听当前对象的哪个属性
      第三个参数: 监听到属性改变之后, 传递什么值
      第四个参数: 需要传递的参数 (这个参数不是传递给属性的)
 */
  // 给p这个对象添加一个监听 , 监听p对象的age属性的改变, 只要age属性改变就通知self 
 [p1 addObserver:self forKeyPath:@"age" options:NSKeyValueObservingOptionOld | NSKeyValueObservingOptionNew context:nil];  // 枚举,可连写可以用“|”分隔
3.实现监听方法 : observeValueForKeyPath
// 只要监听到属性的改变就会调用
        // keyPath: 被监听的属性名称
        // object : 被监听的对象
        // context: 注册监听的时候传入的值
- (void)observeValueForKeyPath:(nullable NSString *)keyPath ofObject:(nullable id)object change:(nullable NSDictionary *)change context:(nullable void *)context{
 // 对比change字典中new与old,可判断监听属性是变大还是变小.
                int new = [change[NSKeyValueChangeNewKey] intValue]; // 取key为new对应的值
                int old = [change[NSKeyValueChangeOldKey] intValue]; // 取key为old对应的值

                NSLog(@"keyPath = %@, object = %@ , change = %@, context = %@", keyPath, object, change, context);
        }  

4.对象销毁一定要移除监听

// 从p对象上移除self对它的age属性的监听
 [p1 removeObserver:self forKeyPath:@"age"];

5.监听person的age属性改变,通过set方法修改,就会触发observeValueForKeyPath方法,监听到age属性的改变

 p1.age = 12; // 调用了set方法

注意: KVO只能监听通过set方法修改的值

p1->_age = 88; // 不会监听到,因为KVO只监听通过set方法修改的属性值,而p->age并不是通过set方法修改属性值的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值