前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RAC(ReactiveCocoa)介绍(八)——KVO销毁

RAC(ReactiveCocoa)介绍(八)——KVO销毁

作者头像
我只不过是出来写写代码
发布2019-04-02 14:59:38
1.4K0
发布2019-04-02 14:59:38
举报
文章被收录于专栏:我只不过是出来写写iOS

上一篇探究了RAC的销毁机制,既然说到销毁,就不得不说下RAC中的KVO销毁。

在RAC中使用KVO时,仅需一行代码,即可完成对指定对象的属性变化值监听,而且不再需要时刻关注KVO销毁。在这一行代码中,RAC内部是如何自动完成KVO的销毁管理?

代码语言:javascript
复制
    [RACObserve(self.testLable, text) subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

宏定义RACObserve方法实现中,可以发现- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;方法。

代码语言:javascript
复制
#define _RACObserve(TARGET, KEYPATH) \
({ \
    __weak id target_ = (TARGET); \
    [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
})

进入- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer方法实现

代码语言:javascript
复制
- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer {
    return [[[self
        rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]
        map:^(RACTuple *value) {
            // -map: because it doesn't require the block trampoline that -reduceEach: uses
            return value[0];
        }]
        setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath];
}

在实现方法中,可以发现使用了map映射方法,当KVO监听属性时,会有多个数据通过元组的形式返回,此时只取元组中的第一个值,即newValue。为什么要去元组value的第一个值,这时打印一下value就会发现:

RAC_KVO属性值打印结果

value中以元组类型存在的数据,与KVO本身监听属性值变化时的打印值非常相像。那么value中的第一个元素,即为RAC KVO方法监听到的新属性值。

深入探究主要带着目的去查看:如何实现内部管理销毁KVO

在该RAC实现方法中,既然是要探究如何在RAC内部方法中如何销毁KVO,那么直接寻找返回RACDisposable类型的代码。在代码实现中,发现下面该方法返回了一个RACDisposable类型数据,即为销毁信号。

代码语言:javascript
复制
            return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
                [subscriber sendNext:RACTuplePack(value, change)];
            }];

继续深入该方法的实现过程,会在该方法中找到组合式销毁信号RACCompoundDisposable,组合式销毁与RACDisposable区别在于,组合式销毁能够将多个销毁信号保存并在执行销毁操作时,将保存的所有销毁信号进行销毁操作。

RACCompoundDisposable类中,声明了一个CF可变数组_disposables,并提供了相应的初始化、添加销毁信号、移除销毁信号操作。

RACCompoundDisposable

RACKVOTrampoline类初始化

进入到该方法中,会发现该方法将keyPath、block、target、strongTarget、observer属性保存至成员变量中。为什么要保存至成员变量中,是因为主要作用于RAC的信号销毁机制。RAC销毁机制可查看上一篇文章RAC信号销毁

代码语言:javascript
复制
- (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {
    NSCParameterAssert(keyPath != nil);
    NSCParameterAssert(block != nil);

    NSObject *strongTarget = target;
    if (strongTarget == nil) return nil;

    self = [super init];

    _keyPath = [keyPath copy];

    _block = [block copy];
    _weakTarget = target;
    _unsafeTarget = strongTarget;
    _observer = observer;

    [RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
    [strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];

    [strongTarget.rac_deallocDisposable addDisposable:self];
    [self.observer.rac_deallocDisposable addDisposable:self];

    return self;
}

其中一行代码实现的方法与系统中KVO方法对比后,会发现此处就是对系统KVO方法的封装。

代码语言:javascript
复制
//RAC内部方法
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
//系统KVO实现方法
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

RACKVOTrampoline类继承自RACDisposable父类,其中有实现dispose销毁方法。在RAC探究过程中,已经知道在RACSignal信号销毁时,都会执行手动销毁+自动销毁信号的流程。当执行dispose方法销毁时,RACKVOTrampoline类实现了对系统KVO监听者的remove移除操作。

代码语言:javascript
复制
- (void)dispose {
    NSObject *target;
    NSObject *observer;

    @synchronized (self) {
        _block = nil;

        // The target should still exist at this point, because we still need to
        // tear down its KVO observation. Therefore, we can use the unsafe
        // reference (and need to, because the weak one will have been zeroed by
        // now).
        target = self.unsafeTarget;
        observer = self.observer;

        _unsafeTarget = nil;
        _observer = nil;
    }

    [target.rac_deallocDisposable removeDisposable:self];
    [observer.rac_deallocDisposable removeDisposable:self];
 //调用了KVO的remove移除方法
    [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
    [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}

通过层层查看代码实现,最终找到了RAC内部是大体如何实现KVO监听者的remove移除操作。RAC本身实际上是对系统KVO监听者的封装,将KVO监听者的创建与销毁操作放入销毁信号RACDisposable类的子类:RACKVOTrampoline。通过RAC的手动+自动销毁信号机制,在dispose方法中实现对KVO监听者的remove操作。最终达成RAC KVO的内部自动管理remove监听者KVO的目的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2018.05.30 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档