上一篇探究了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):

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)操作。


進(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 博客