RACDisposable算是三個(gè)核心組件里面最簡(jiǎn)單的了, 除了自身外, 還有4個(gè)子類:
RACKVOTrampoline, RACScopedDisposable 以及在Signal中已經(jīng)介紹過(guò)的RACCompoundDisposable和RACSerialDisposable. 這一部分的代碼還是比較好理解的, 就是有很多底層一些的代碼, 所以需要多查查文檔.
RACDisposable
頭文件對(duì)這個(gè)類的描述就是對(duì)訂閱關(guān)系的取消和相關(guān)資源的清理, 我們就看看它是怎么清理的.
// RACDisposable.h
// 標(biāo)記是否已經(jīng)清除的狀態(tài)
@property (atomic, assign, getter = isDisposed, readonly) BOOL disposed;
+ (instancetype)disposableWithBlock:(void (^)(void))block;
- (void)dispose;
- (RACScopedDisposable *)asScopedDisposable; // 轉(zhuǎn)換為RACScopedDisposable
屬性和方法的意義還是比較明顯的, 然后看實(shí)現(xiàn)文件也比較"言簡(jiǎn)意賅", 大致意思是存儲(chǔ)起來(lái)dispose需要的block, 在調(diào)用時(shí)執(zhí)行這個(gè)block(如果block不為空)[注意, 如果不是所有的RACDisposable在dealloc時(shí)都會(huì)自動(dòng)調(diào)用dispose喲]. 但是里面的實(shí)現(xiàn)用到了很多C語(yǔ)言和一些非ARC的東西, 所以看起來(lái)比較高深.
先看生命周期函數(shù):
// 一個(gè)實(shí)際上沒(méi)有什么可清除的disposable, 基本上可以看做一個(gè)標(biāo)記是否已dispose的值
- (id)init {
self = [super init];
if (self == nil) return nil;
// 需要注意: 如果沒(méi)有block, _disposeBlock會(huì)指向自己, 所以后續(xù)操作都會(huì)進(jìn)行判斷是否等于自己, 因此_disposeBlock的類型也是void *. 之所以不是id類型, 是因?yàn)闀?huì)引用自己, 這樣就循環(huán)引用了.
_disposeBlock = (__bridge void *)self;
// OSMemoryBarrier是確保前面的代碼執(zhí)行完了之后再執(zhí)行后面的,
// 這個(gè)在多核CPU中可以保證安全
OSMemoryBarrier();
return self;
}
- (id)initWithBlock:(void (^)(void))block {
NSCParameterAssert(block != nil);
self = [super init];
if (self == nil) return nil;
// 這里其實(shí)不是真正的retain, 只是一個(gè)橋接, 把Objc類型轉(zhuǎn)換為CoreFoundation類型(也就是C類型), 因?yàn)開(kāi)disposeBlock是void *類型
_disposeBlock = (void *)CFBridgingRetain([block copy]);
OSMemoryBarrier();
return self;
}
- (void)dealloc {
// 為空和等于自身都不需要額外釋放或者設(shè)置NULL
if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
CFRelease(_disposeBlock);
_disposeBlock = NULL;
}
核心的dispose也是一個(gè)看起來(lái)有點(diǎn)難的函數(shù), 并不像我們想的直接判斷_disposeBlock后調(diào)用.
- (void)dispose {
void (^disposeBlock)(void) = NULL;
while (YES) {
void *blockPtr = _disposeBlock;
// 應(yīng)該又是多核作祟, 所以又要while YES, 又要?jiǎng)傎x值又compare
// 這里blockPtr和_disposeBlock對(duì)比匹配后, 會(huì)把_disposeBlock賦值為NULL
// 所以isDisposed只需要判斷_disposeBlock == NULL即可
if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
// 如果不等于self, 說(shuō)明外面有block傳進(jìn)來(lái)
if (blockPtr != (__bridge void *)self) {
//CoreFoundation類型轉(zhuǎn)換為Objc類型
disposeBlock = CFBridgingRelease(blockPtr);
}
break;
}
}
// 執(zhí)行block(如果有)
if (disposeBlock != nil) disposeBlock();
}
RACScopedDisposable
RACDisposable最后有個(gè)asScopedDisposable方法, 就是直接返回了一個(gè)RACScopedDisposable對(duì)象, 與父類的區(qū)別就是, 這個(gè)類的實(shí)例在dealloc時(shí)會(huì)調(diào)用dispose.
下面就是全部代碼, 還是比較明顯的
+ (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable {
// 自身沒(méi)有什么好釋放的, 直接調(diào)用參數(shù)的dispose
return [self disposableWithBlock:^{
[disposable dispose];
}];
}
- (void)dealloc {
[self dispose];
}
#pragma mark RACDisposable
// 重寫(xiě)父類的方法返回自己, 不然再次調(diào)用就又換一個(gè)實(shí)例
- (RACScopedDisposable *)asScopedDisposable {
// totally already are
return self;
}
RACKVOTrampoline
頭文件中介紹這類對(duì)象用于KVO觀察模式中. 所以最好還是和KVO相關(guān)的信號(hào)一起看, 但是代碼也并不復(fù)雜, 所以可以先行探討一下.
子類頭文件只有一個(gè)方法:
- (id)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block;
私有屬性:
@interface RACKVOTrampoline ()
// 正在觀察的keyPath
@property (nonatomic, readonly, copy) NSString *keyPath;
// 回調(diào)block
@property (nonatomic, readonly, copy) RACKVOBlock block;
// unsafe_unretained意味著這個(gè)屬性要純粹自己管理, 編譯器不會(huì)對(duì)這個(gè)屬性做任何ARC操作
@property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget;
@property (nonatomic, readonly, weak) NSObject *weakTarget;
@property (nonatomic, readonly, weak) NSObject *observer;
@end
方法實(shí)現(xiàn):
- (id)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];
if (self == nil) return nil;
_keyPath = [keyPath copy];
_block = [block copy];
_weakTarget = target;
_unsafeTarget = strongTarget;
_observer = observer;
// 在RACKVOProxy.sharedProxy注冊(cè)觀察者 傳入context是過(guò)濾掉不屬于自己范圍的回調(diào), 里面涉及到RACKVOProxy.sharedProxy的實(shí)現(xiàn), 這個(gè)之后再看
[RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
// 真正監(jiān)聽(tīng)的是RACKVOProxy.sharedProxy
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
// 在strongTarget和observer被釋放后, 要執(zhí)行自己的dispose
[strongTarget.rac_deallocDisposable addDisposable:self];
[self.observer.rac_deallocDisposable addDisposable:self];
return self;
}
// 和scoped一樣, 在dealloc時(shí)會(huì)調(diào)用dispose
- (void)dealloc {
[self dispose];
}
本身也在KVOProxy中注冊(cè)了觀察者, 所以肯定還有回調(diào)方法:
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (context != (__bridge void *)self) {
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
return;
}
RACKVOBlock block;
id observer;
id target;
// 沒(méi)有什么特別的, 保證線程安全的情況下, 回調(diào)即可
@synchronized (self) {
block = self.block;
observer = self.observer;
target = self.weakTarget;
}
if (block == nil || target == nil) return;
block(target, observer, change);
}
看看作為一個(gè)Disposable的關(guān)鍵方法:
- (void)dispose {
NSObject *target;
NSObject *observer;
// 主要是清理持有的對(duì)象
@synchronized (self) {
_block = nil;
// target雖然是unsafe的, 但是這個(gè)時(shí)候target應(yīng)該還未釋放, 因?yàn)樵趇nit方法中, 對(duì)target的rac_deallocDisposable進(jìn)行了add self的操作, 如果要釋放了, 則會(huì)自動(dòng)調(diào)用這方法
target = self.unsafeTarget;
observer = self.observer;
_unsafeTarget = nil;
_observer = nil;
}
// 移除添加的disposable
[target.rac_deallocDisposable removeDisposable:self];
[observer.rac_deallocDisposable removeDisposable:self];
// 移除觀察者
[target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
[RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}
RACCompoundDisposable
本質(zhì)上可以看做一個(gè)Disposable數(shù)組, 在dispose的時(shí)候會(huì)把組合進(jìn)來(lái)的Disposable一個(gè)個(gè)調(diào)用dispose.
內(nèi)部的實(shí)現(xiàn)用了C數(shù)組和CoreFoundation的數(shù)組而不是一個(gè)Objc的Array, 原因應(yīng)該一是性能方面的考慮, 因?yàn)镃ompoundDisposable用的很頻繁, 二是會(huì)持有這個(gè)Disposable, 有一些類型的Disposable是在dealloc的時(shí)候要dispose的, 如果持有則會(huì)干擾這個(gè)行為.
同時(shí), 實(shí)現(xiàn)還用了一個(gè)魔數(shù)長(zhǎng)度的固定大小數(shù)組, 更多的disposable會(huì)額外存儲(chǔ)在一個(gè)CoreFoundation創(chuàng)建的數(shù)組中. 有2個(gè)問(wèn)題:
- 為什么要分為2個(gè)部分?
- 為什么這個(gè)數(shù)字是2?
第一個(gè)問(wèn)題的答案是性能, 用CoreFoundation是比較耗時(shí)的, 而直接用一個(gè)固定大小的C數(shù)組會(huì)更快.
第二個(gè)問(wèn)題的答案還是性能, 只不過(guò)這個(gè)是作者綜合測(cè)算出來(lái)的.
#define RACCompoundDisposableInlineCount 2
基于上面的緣故, 這里實(shí)現(xiàn)會(huì)看起來(lái)比較復(fù)雜一點(diǎn), 但是實(shí)際上還是比較好懂的, 看成對(duì)數(shù)組的操作即可.
- (id)initWithDisposables:(NSArray *)otherDisposables {
self = [self init];
if (self == nil) return nil;
#if RACCompoundDisposableInlineCount
[otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) {
// 前2個(gè)存在inline數(shù)組中, 也就是C數(shù)組
_inlineDisposables[index] = disposable;
// 超過(guò)2個(gè)的先不管
if (index == RACCompoundDisposableInlineCount - 1) *stop = YES;
}];
#endif
// 大于2個(gè)的創(chuàng)建CoreFoundation數(shù)組來(lái)管理
if (otherDisposables.count > RACCompoundDisposableInlineCount) {
_disposables = RACCreateDisposablesArray();
// 寫(xiě)入數(shù)據(jù)
CFRange range = CFRangeMake(RACCompoundDisposableInlineCount, (CFIndex)otherDisposables.count - RACCompoundDisposableInlineCount);
CFArrayAppendArray(_disposables, (__bridge CFArrayRef)otherDisposables, range);
}
return self;
}
// dealloc不會(huì)自動(dòng)調(diào)用dispose
- (void)dealloc {
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
_inlineDisposables[i] = nil;
}
#endif
if (_disposables != NULL) {
CFRelease(_disposables);
_disposables = NULL;
}
}
添加/刪除Disposable的操作:
- (void)addDisposable:(RACDisposable *)disposable {
NSCParameterAssert(disposable != self);
if (disposable == nil || disposable.disposed) return;
BOOL shouldDispose = NO;
// 保證線程安全
OSSpinLockLock(&_spinLock);
{
// 如果此時(shí)已經(jīng)dispose掉了, 那么也要對(duì)該disposable調(diào)用dispose
if (_disposed) {
shouldDispose = YES;
} else {
// 主體代碼:
// 1. 先找找inline數(shù)組里面有沒(méi)有空位
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
if (_inlineDisposables[i] == nil) {
// 有就賦值, 然后跳到后面去執(zhí)行
_inlineDisposables[i] = disposable;
goto foundSlot;
}
}
#endif
// 2. 如果已經(jīng)滿額, 就加入到CoreFoundation中
if (_disposables == NULL) _disposables = RACCreateDisposablesArray();
CFArrayAppendValue(_disposables, (__bridge void *)disposable);
// 下面是加入了DTrace探針的代碼?
if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
}
#if RACCompoundDisposableInlineCount
foundSlot:;
#endif
}
}
OSSpinLockUnlock(&_spinLock);
// 在鎖外面調(diào)用, 防止遞歸使用CompoundDisposable
if (shouldDispose) [disposable dispose];
}
// remove的操作基本差不多, 主要是一些C函數(shù)的使用
- (void)removeDisposable:(RACDisposable *)disposable {
if (disposable == nil) return;
OSSpinLockLock(&_spinLock);
{
if (!_disposed) {
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
// 這里既然已經(jīng)找到了, 為什么不跳到最后呢? 難道就是為了少寫(xiě)一對(duì)大括號(hào)么,[手動(dòng)摳鼻]
if (_inlineDisposables[i] == disposable) _inlineDisposables[i] = nil;
}
#endif
if (_disposables != NULL) {
CFIndex count = CFArrayGetCount(_disposables);
for (CFIndex i = count - 1; i >= 0; i--) {
const void *item = CFArrayGetValueAtIndex(_disposables, i);
if (item == (__bridge void *)disposable) {
CFArrayRemoveValueAtIndex(_disposables, i);
}
}
if (RACCOMPOUNDDISPOSABLE_REMOVED_ENABLED()) {
RACCOMPOUNDDISPOSABLE_REMOVED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
}
}
}
}
OSSpinLockUnlock(&_spinLock);
}
至于核心的dispose, 顯然就會(huì)是2個(gè)數(shù)組的遍歷了:
- (void)dispose {
// 1. 把2個(gè)數(shù)組copy出來(lái)到本地
// 這么做一是可以保證線程安全(局部變量是線程安全的)
// 而是可以盡早解開(kāi)鎖
#if RACCompoundDisposableInlineCount
RACDisposable *inlineCopy[RACCompoundDisposableInlineCount];
#endif
CFArrayRef remainingDisposables = NULL;
OSSpinLockLock(&_spinLock);
{
_disposed = YES;
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
inlineCopy[i] = _inlineDisposables[i];
_inlineDisposables[i] = nil;
}
#endif
remainingDisposables = _disposables;
_disposables = NULL;
}
OSSpinLockUnlock(&_spinLock);
#if RACCompoundDisposableInlineCount
// 遍歷inline數(shù)組 調(diào)用dispose
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
[inlineCopy[i] dispose];
}
#endif
if (remainingDisposables == NULL) return;
// 額外的Disposables要傳入函數(shù)指針來(lái)遍歷然后調(diào)用dispose
CFIndex count = CFArrayGetCount(remainingDisposables);
CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL);
CFRelease(remainingDisposables);
}
static void disposeEach(const void *value, void *context) {
RACDisposable *disposable = (__bridge id)value;
[disposable dispose];
}
整體來(lái)說(shuō)上面的代碼還是比較易懂的, 就是有很多C級(jí)別的代碼, 很多API都比較底層.
RACSerialDisposable
Signal中說(shuō)了對(duì)RACSerialDisposable調(diào)用setDisposable會(huì)有額外的一個(gè)效果, 舊的值如果已經(jīng)被dispose了, 那么新的值也會(huì)立即dispose掉.
這個(gè)類的頭文件也比較簡(jiǎn)單, 一個(gè)屬性2個(gè)方法, 私有屬性還有一些線程安全和狀態(tài)以及輔助操作的聲明(屬性聲明了disposable, 在拓展里面還要寫(xiě)RACDisposable * _disposable是因?yàn)閷?shí)現(xiàn)方法重寫(xiě)了其getter方法--也就是disposable方法, 而在里面又要訪問(wèn)這個(gè)值, 為了避免造成遞歸, 所以需要直接訪問(wèn), 而不能self.的形式訪問(wèn)).
直接看下這2個(gè)getter和setter
- (RACDisposable *)disposable {
// 保證線程安全, 因?yàn)橛锌赡軙?huì)經(jīng)常變化
RACDisposable *result;
OSSpinLockLock(&_spinLock);
result = _disposable;
OSSpinLockUnlock(&_spinLock);
return result;
}
- (void)setDisposable:(RACDisposable *)disposable {
[self swapInDisposable:disposable];
}
// 核心方法
- (RACDisposable *)swapInDisposable:(RACDisposable *)newDisposable {
RACDisposable *existingDisposable;
BOOL alreadyDisposed;
OSSpinLockLock(&_spinLock);
// 判斷是否已經(jīng)dispose過(guò)
alreadyDisposed = _disposed;
if (!alreadyDisposed) {
// 如果沒(méi)有, 則把新Disposable賦給屬性, 局部變量存儲(chǔ)老的Disposable
existingDisposable = _disposable;
_disposable = newDisposable;
}
OSSpinLockUnlock(&_spinLock);
// 如果老的已經(jīng)dispose過(guò)了, 那么新的也直接dispose掉, 返回空
if (alreadyDisposed) {
[newDisposable dispose];
return nil;
}
// 返回老的Disposable
return existingDisposable;
}
dispose方法則沒(méi)什么特別:
- (void)dispose {
RACDisposable *existingDisposable;
OSSpinLockLock(&_spinLock);
if (!_disposed) {
existingDisposable = _disposable;
_disposed = YES;
_disposable = nil;
}
OSSpinLockUnlock(&_spinLock);
[existingDisposable dispose];
}