RAC(ReactiveCocoa)介紹(八)——KVO銷毀

上一篇探究了RAC的銷毀機(jī)制,既然說(shuō)到銷毀,就不得不說(shuō)下RAC中的KVO銷毀。
在RAC中使用KVO時(shí),僅需一行代碼,即可完成對(duì)指定對(duì)象的屬性變化值監(jiān)聽(tīng),而且不再需要時(shí)刻關(guān)注KVO銷毀。在這一行代碼中,RAC內(nèi)部是如何自動(dòng)完成KVO的銷毀管理?

    [RACObserve(self.testLable, text) subscribeNext:^(id  _Nullable x) {
        NSLog(@"%@",x);
    }];

宏定義RACObserve方法實(shí)現(xiàn)中,可以發(fā)現(xiàn)- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer;方法。

#define _RACObserve(TARGET, KEYPATH) \
({ \
    __weak id target_ = (TARGET); \
    [target_ rac_valuesForKeyPath:@keypath(TARGET, KEYPATH) observer:self]; \
})

進(jìn)入- (RACSignal *)rac_valuesForKeyPath:(NSString *)keyPath observer:(__weak NSObject *)observer方法實(shí)現(xiàn)

- (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];
}

在實(shí)現(xiàn)方法中,可以發(fā)現(xiàn)使用了map映射方法,當(dāng)KVO監(jiān)聽(tīng)屬性時(shí),會(huì)有多個(gè)數(shù)據(jù)通過(guò)元組的形式返回,此時(shí)只取元組中的第一個(gè)值,即newValue。為什么要去元組value的第一個(gè)值,這時(shí)打印一下value就會(huì)發(fā)現(xiàn):

RAC_KVO屬性值打印結(jié)果

value中以元組類型存在的數(shù)據(jù),與KVO本身監(jiān)聽(tīng)屬性值變化時(shí)的打印值非常相像。那么value中的第一個(gè)元素,即為RAC KVO方法監(jiān)聽(tīng)到的新屬性值。

深入探究主要帶著目的去查看:如何實(shí)現(xiàn)內(nèi)部管理銷毀KVO

在該RAC實(shí)現(xiàn)方法中,既然是要探究如何在RAC內(nèi)部方法中如何銷毀KVO,那么直接尋找返回RACDisposable類型的代碼。在代碼實(shí)現(xiàn)中,發(fā)現(xiàn)下面該方法返回了一個(gè)RACDisposable類型數(shù)據(jù),即為銷毀信號(hào)。

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

繼續(xù)深入該方法的實(shí)現(xiàn)過(guò)程,會(huì)在該方法中找到組合式銷毀信號(hào)RACCompoundDisposable,組合式銷毀與RACDisposable區(qū)別在于,組合式銷毀能夠?qū)⒍鄠€(gè)銷毀信號(hào)保存并在執(zhí)行銷毀操作時(shí),將保存的所有銷毀信號(hào)進(jìn)行銷毀操作。
RACCompoundDisposable類中,聲明了一個(gè)CF可變數(shù)組_disposables,并提供了相應(yīng)的初始化、添加銷毀信號(hào)、移除銷毀信號(hào)操作。

RACCompoundDisposable

RACKVOTrampoline類初始化

進(jìn)入到該方法中,會(huì)發(fā)現(xiàn)該方法將keyPath、block、target、strongTarget、observer屬性保存至成員變量中。為什么要保存至成員變量中,是因?yàn)橹饕饔糜赗AC的信號(hào)銷毀機(jī)制。RAC銷毀機(jī)制可查看上一篇文章RAC信號(hào)銷毀

- (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;
}

其中一行代碼實(shí)現(xiàn)的方法與系統(tǒng)中KVO方法對(duì)比后,會(huì)發(fā)現(xiàn)此處就是對(duì)系統(tǒng)KVO方法的封裝。

//RAC內(nèi)部方法
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
//系統(tǒng)KVO實(shí)現(xiàn)方法
- (void)addObserver:(NSObject *)observer forKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options context:(nullable void *)context;

RACKVOTrampoline類繼承自RACDisposable父類,其中有實(shí)現(xiàn)dispose銷毀方法。在RAC探究過(guò)程中,已經(jīng)知道在RACSignal信號(hào)銷毀時(shí),都會(huì)執(zhí)行手動(dòng)銷毀+自動(dòng)銷毀信號(hào)的流程。當(dāng)執(zhí)行dispose方法銷毀時(shí),RACKVOTrampoline類實(shí)現(xiàn)了對(duì)系統(tǒng)KVO監(jiān)聽(tīng)者的remove移除操作。

- (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];
 //調(diào)用了KVO的remove移除方法
    [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
    [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}

通過(guò)層層查看代碼實(shí)現(xiàn),最終找到了RAC內(nèi)部是大體如何實(shí)現(xiàn)KVO監(jiān)聽(tīng)者的remove移除操作。RAC本身實(shí)際上是對(duì)系統(tǒng)KVO監(jiān)聽(tīng)者的封裝,將KVO監(jiān)聽(tīng)者的創(chuàng)建與銷毀操作放入銷毀信號(hào)RACDisposable類的子類:RACKVOTrampoline。通過(guò)RAC的手動(dòng)+自動(dòng)銷毀信號(hào)機(jī)制,在dispose方法中實(shí)現(xiàn)對(duì)KVO監(jiān)聽(tīng)者的remove操作。最終達(dá)成RAC KVO的內(nèi)部自動(dòng)管理remove監(jiān)聽(tīng)者KVO的目的。

該文章首次發(fā)表在 簡(jiǎn)書(shū):我只不過(guò)是出來(lái)寫寫代碼 博客,并自動(dòng)同步至 騰訊云:我只不過(guò)是出來(lái)寫寫iOS 博客

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容