KVO介绍

作者: 深度码农患者 | 来源:发表于2020-02-22 21:41 被阅读0次
概述

KVO是苹果提供的一套事件通知机制,允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的实现机制,所以对属性才会发生作用,一般继承自NSObject的对象都默认支持KVO。
KVO和NSNotification都是iOS中对观察者模式的一种实现。区别在于,相对于观察者和被观察者的关系,KVO是一对一的,而不是一对多的。KVO对被监听对象无侵入性,不需要修改其内部代码就可以实现监听。
KVO可以监听单个属性的变化,也可以监听集合对象的变化。

实现原理

KVO是通过isa-swizzling技术实现的,在运行时根据原类创建一个中间类,这个中间类是原类的子类,并动态修改当前对象的isa指针指向中间类。将Class方法重写,返回原类的Class,所以苹果建议在开发中不应该依赖isa指针,而是通过class实例方法来获取对象类型。

缺点

苹果提供的KVO自身存在很多问题,首先问题在于,KVO如果使用不当很容易崩溃,比如说重复的add和remove导致的崩溃,Observer被释放导致的崩溃,keypath传错导致的崩溃等等。
由于keyPath是字符串的形式,所以在其对象的属性名发生改变之后,字符串没有被改变很容易导致崩溃。我们可以利用系统的反射机制将keyPath反射出来,这样编译器可以在@selector()中进行合法性检查。

自己实现KVO
  1. 可以在NSObject的分类中实现
  2. 实现addObserver:forKey:with:方法
  • 检查对象的类有没有响应的setter方法,如果没有则抛出异常。
  • 检查对象isa指指针指向的类是不是一个KVO类,如果不是,新建一个继承当前类的子类,并把isa指针指向这个类。
  • 检查对象的KVO类是否重写过setter方法,如果没有,添加重写的setter方法
  • 添加观察者
    具体来说,有以下步骤:
  1. 通过setterFirGeter方法获得相应的setter的方法名,也就是key的首字母大写,然后再前面加载set后面加上:,变成setKey:。然后再用class_getInstanceMethod去获取setKey:的实现,如果没有,再抛出异常。
  2. 看类名有没有我们定义的前缀,如果没有,我们去创建新的子类,并通过object_setClass()去修改isa指针。
    动态创建新的类需要runtime中定义的objc_allocateClassPair()函数。传一个父类名以及额外的空间,会返回一个雷,然后给这个类添加方法和变量。
- (Class)makeKvoClassWithOriginalClassName:(NSString *)originalClazzName
{
    NSString *kvoClazzName = [kPGKVOClassPrefix stringByAppendingString:originalClazzName];
    Class clazz = NSClassFromString(kvoClazzName);

    if (clazz) {
        return clazz;
    }

    // class doesn't exist yet, make it
    Class originalClazz = object_getClass(self);
    Class kvoClazz = objc_allocateClassPair(originalClazz, kvoClazzName.UTF8String, 0);

    // grab class method's signature so we can borrow it
    Method clazzMethod = class_getInstanceMethod(originalClazz, @selector(class));
    const char *types = method_getTypeEncoding(clazzMethod);
    class_addMethod(kvoClazz, @selector(class), (IMP)kvo_class, types);

    objc_registerClassPair(kvoClazz);

    return kvoClazz;
}
  1. 重写setter方法。新的setter在调用原setter方法后,通知每个观察者。
- (Class)makeKvoClassWithOriginalClassName:(NSString *)originalClazzName
{
    NSString *kvoClazzName = [kPGKVOClassPrefix stringByAppendingString:originalClazzName];
    Class clazz = NSClassFromString(kvoClazzName);

    if (clazz) {
        return clazz;
    }

    // class doesn't exist yet, make it
    Class originalClazz = object_getClass(self);
    Class kvoClazz = objc_allocateClassPair(originalClazz, kvoClazzName.UTF8String, 0);

    // grab class method's signature so we can borrow it
    Method clazzMethod = class_getInstanceMethod(originalClazz, @selector(class));
    const char *types = method_getTypeEncoding(clazzMethod);
    class_addMethod(kvoClazz, @selector(class), (IMP)kvo_class, types);

    objc_registerClassPair(kvoClazz);

    return kvoClazz;
}
  1. 把观察的相关信息存在associatedObject中。
@interface PGObservationInfo : NSObject

@property (nonatomic, weak) NSObject *observer;
@property (nonatomic, copy) NSString *key;
@property (nonatomic, copy) PGObservingBlock block;

@end

相关文章

  • KVO与KVC原理

    KVO 一、KVO的介绍 1、什么是KVO KVO的全称是Key-Value Observing的缩写,是对观...

  • KVO介绍

    KVO全称Key Value Observing.直译为键值观察。KVO主要用于视觉交互方面,比如当某些数据变化了...

  • KVO介绍

    概述 KVO是苹果提供的一套事件通知机制,允许对象监听另一个对象特定属性的改变,并在改变时接收到事件。由于KVO的...

  • KVO&KVC

    一 KVO a) 介绍:Objective-C 中的键(key)-值(value)观察(KVO)来源...

  • 十:KVO底层原理探究

    KVO介绍: KVO,全称为Key-Value observing,中文名为键值观察,KVO是一种机制,它允许将其...

  • iOS OC KVO使用+原理+自定义

    首先先抛出来几个问题: 在讨论KVO之前,先看下官方文档给的KVO介绍: 1、什么是KVO KVO俗称键值观察(k...

  • Swift - RxSwift的使用详解64(键值观察KVO的使

    一、基本介绍 1,KVO 介绍 KVO(键值观察)是一种 Objective-C 的回调机制,全称为:key-va...

  • KVO 的总结

    kvo 1.kvo介绍 KVO是一种允许对象在其他对象的指定属性发生变化时被通知的机制。 重点:为了理解KVO,首...

  • KVO里面的(void *)context

    KVO中context介绍 一直使用KVO却很少关注context这个变量,这个变量来源于自己添加KVO监听的时候...

  • KVO与KVC

    KVO与KVC是观察者模式在iOS中的一种实现 KVO 一、KVO的介绍 KVO就是观察者模式,说白了就是你关心的...

网友评论

      本文标题:KVO介绍

      本文链接:https://www.haomeiwen.com/subject/lsurqhtx.html