07-KVO的底层分析

2021-10-24  本文已影响0人  iOS之文一

OC底层原理探索文档汇总

主要内容:
KVO的使用
KVO的底层实现

查阅KVO官方文档

key-value-observing(键值观察)
简单来说就是通过一个key来找到某个属性并监听其值的改变,KVC是实现KVO的基础,因为需要键值监听,KVO只能实现属性的监听,也就是有setter方法的监听,其他的比如成员变量是不行的。

KVO的简单使用

普通的属性设置

  1. 添加观察者
[self.person addObserver:self forKeyPath:@"nick" options:NSKeyValueObservingOptionNew context:NULL];

参数:

说明:

option:

NSKeyValueObservingOptionNew:change字典包括改变后的值
NSKeyValueObservingOptionOld:change字典包括改变前的值
NSKeyValueObservingOptionInitial:注册后立刻触发KVO通知
NSKeyValueObservingOptionPrior:值改变前是否也要通知(这个key决定了是否在改变前改变后通知两次)

  1. 在观察者中实现监听方法
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id>*)change context:(void *)context{

参数:
keyPath:监听的属性
object:被监听者
change:表示数据修改的方式:
context:添加监听时的上下文参数

说明:

NSKeyValueChangeKey类型

typedef NS_ENUM(NSUInteger, NSKeyValueChange) {
    NSKeyValueChangeSetting = 1,//设值
    NSKeyValueChangeInsertion = 2,//集合插入值
    NSKeyValueChangeRemoval = 3,//集合移除值
    NSKeyValueChangeReplacement = 4,//集合替换值
};
  1. 移除观察者
[a removeObserver:b forKeyPath:];

说明:

为什么不移除观察者会崩溃:

属性依赖

如果我们想要监听一个属性,但是这个属性的变化不是直接修改的,而是通过其他几个属性的修改来影响的,这就是属性依赖。
也就是说我们通过监听其他值,响应目标值。两个值的观察变成一个值的观察,观察到两个值中只要有一个进行变化,即进行结果返回。

其他的都和普通的实现一样,重点在于keyPathsForValuesAffectingValueForKeyAPI的使用

+ (NSSet<NSString *> *)keyPathsForValuesAffectingValueForKey:(NSString *)key{
    
    NSSet *keyPaths = [super keyPathsForValuesAffectingValueForKey:key];
    //判断是真正要监听的那个属性
    if ([key isEqualToString:@"downloadProgress"]) {
        //添加keyPaths,这个数组里的每个属性发生变化都会响应观察
        NSArray *affectingKeys = @[@"totalData", @"writtenData"];
        keyPaths = [keyPaths setByAddingObjectsFromArray:affectingKeys];
    }
    return keyPaths;
}

数组的设置

重点需要注意数组元素改变和数组本身的改变是不一样的,对于集合类型的操作一定要注意我们操作的方式,这里需要用到KVC来观察数组属性的改变。

代码:

// 5: 数组观察
    self.person.dateArray = [NSMutableArray arrayWithCapacity:1];
    //观察者数组的KVO,必须利用KVC的原理机制才可以观察到
    [self.person addObserver:self forKeyPath:@"dateArray" options:(NSKeyValueObservingOptionNew) context:NULL];

说明:

手动和自动设置开关

系统默认支持KVO的通知发送,同时系统也提供了一个入口,让我们可以手动去设置是否需要支持发送,如果对这个类关闭了自动开关后,还可以针对其中的某个属性进行手动开启。
手动设置开关可以让我们灵活的加上自己想要的判断条件

代码:

// 自动开关
+ (BOOL) automaticallyNotifiesObserversForKey:(NSString *)key{
//    return YES;//自动
    return NO;//手动,自己写setter
}
//这两个方法都是系统自动监听时要使用的方法,如果不自动监听,就需要我们自己加了。
- (void)setNick:(NSString *)nick{
    [self willChangeValueForKey:@"nick"];
    _nick = nick;
    [self didChangeValueForKey:@"nick"];
}

说明:

小结:

  1. KVO的使用都是三步曲,添加观察者,观察响应,移除观察者
  2. 我们可以自己控制是否需要进行观察
  3. 对于数组的观察需要使用KVC进行设值
  4. 通过属性依赖,可以对有依赖性质的属性进行观察

KVO的底层实现

核心就是新建了一个中间类,是当前类的子类,在setter方法中增加了两个方法,这样就可以进行观察了。

底层的实现过程

底层实现图.png

注意:

上一篇下一篇

猜你喜欢

热点阅读