RACDisposable算是三个核心组件里面最简单的了, 除了自身外, 还有4个子类:
RACKVOTrampoline, RACScopedDisposable 以及在Signal中已经介绍过的RACCompoundDisposable和RACSerialDisposable. 这一部分的代码还是比较好理解的, 就是有很多底层一些的代码, 所以需要多查查文档.
RACDisposable
头文件对这个类的描述就是对订阅关系的取消和相关资源的清理, 我们就看看它是怎么清理的.
// RACDisposable.h
// 标记是否已经清除的状态
@property (atomic, assign, getter = isDisposed, readonly) BOOL disposed;
+ (instancetype)disposableWithBlock:(void (^)(void))block;
- (void)dispose;
- (RACScopedDisposable *)asScopedDisposable; // 转换为RACScopedDisposable
属性和方法的意义还是比较明显的, 然后看实现文件也比较"言简意赅", 大致意思是存储起来dispose需要的block, 在调用时执行这个block(如果block不为空)[注意, 如果不是所有的RACDisposable在dealloc时都会自动调用dispose哟]. 但是里面的实现用到了很多C语言和一些非ARC的东西, 所以看起来比较高深.
先看生命周期函数:
// 一个实际上没有什么可清除的disposable, 基本上可以看做一个标记是否已dispose的值
- (id)init {
self = [super init];
if (self == nil) return nil;
// 需要注意: 如果没有block, _disposeBlock会指向自己, 所以后续操作都会进行判断是否等于自己, 因此_disposeBlock的类型也是void *. 之所以不是id类型, 是因为会引用自己, 这样就循环引用了.
_disposeBlock = (__bridge void *)self;
// OSMemoryBarrier是确保前面的代码执行完了之后再执行后面的,
// 这个在多核CPU中可以保证安全
OSMemoryBarrier();
return self;
}
- (id)initWithBlock:(void (^)(void))block {
NSCParameterAssert(block != nil);
self = [super init];
if (self == nil) return nil;
// 这里其实不是真正的retain, 只是一个桥接, 把Objc类型转换为CoreFoundation类型(也就是C类型), 因为_disposeBlock是void *类型
_disposeBlock = (void *)CFBridgingRetain([block copy]);
OSMemoryBarrier();
return self;
}
- (void)dealloc {
// 为空和等于自身都不需要额外释放或者设置NULL
if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;
CFRelease(_disposeBlock);
_disposeBlock = NULL;
}
核心的dispose也是一个看起来有点难的函数, 并不像我们想的直接判断_disposeBlock后调用.
- (void)dispose {
void (^disposeBlock)(void) = NULL;
while (YES) {
void *blockPtr = _disposeBlock;
// 应该又是多核作祟, 所以又要while YES, 又要刚赋值又compare
// 这里blockPtr和_disposeBlock对比匹配后, 会把_disposeBlock赋值为NULL
// 所以isDisposed只需要判断_disposeBlock == NULL即可
if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
// 如果不等于self, 说明外面有block传进来
if (blockPtr != (__bridge void *)self) {
//CoreFoundation类型转换为Objc类型
disposeBlock = CFBridgingRelease(blockPtr);
}
break;
}
}
// 执行block(如果有)
if (disposeBlock != nil) disposeBlock();
}
RACScopedDisposable
RACDisposable最后有个asScopedDisposable方法, 就是直接返回了一个RACScopedDisposable对象, 与父类的区别就是, 这个类的实例在dealloc时会调用dispose.
下面就是全部代码, 还是比较明显的
+ (instancetype)scopedDisposableWithDisposable:(RACDisposable *)disposable {
// 自身没有什么好释放的, 直接调用参数的dispose
return [self disposableWithBlock:^{
[disposable dispose];
}];
}
- (void)dealloc {
[self dispose];
}
#pragma mark RACDisposable
// 重写父类的方法返回自己, 不然再次调用就又换一个实例
- (RACScopedDisposable *)asScopedDisposable {
// totally already are
return self;
}
RACKVOTrampoline
头文件中介绍这类对象用于KVO观察模式中. 所以最好还是和KVO相关的信号一起看, 但是代码也并不复杂, 所以可以先行探讨一下.
子类头文件只有一个方法:
- (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;
// 回调block
@property (nonatomic, readonly, copy) RACKVOBlock block;
// unsafe_unretained意味着这个属性要纯粹自己管理, 编译器不会对这个属性做任何ARC操作
@property (nonatomic, readonly, unsafe_unretained) NSObject *unsafeTarget;
@property (nonatomic, readonly, weak) NSObject *weakTarget;
@property (nonatomic, readonly, weak) NSObject *observer;
@end
方法实现:
- (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注册观察者 传入context是过滤掉不属于自己范围的回调, 里面涉及到RACKVOProxy.sharedProxy的实现, 这个之后再看
[RACKVOProxy.sharedProxy addObserver:self forContext:(__bridge void *)self];
// 真正监听的是RACKVOProxy.sharedProxy
[strongTarget addObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath options:options context:(__bridge void *)self];
// 在strongTarget和observer被释放后, 要执行自己的dispose
[strongTarget.rac_deallocDisposable addDisposable:self];
[self.observer.rac_deallocDisposable addDisposable:self];
return self;
}
// 和scoped一样, 在dealloc时会调用dispose
- (void)dealloc {
[self dispose];
}
本身也在KVOProxy中注册了观察者, 所以肯定还有回调方法:
- (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;
// 没有什么特别的, 保证线程安全的情况下, 回调即可
@synchronized (self) {
block = self.block;
observer = self.observer;
target = self.weakTarget;
}
if (block == nil || target == nil) return;
block(target, observer, change);
}
看看作为一个Disposable的关键方法:
- (void)dispose {
NSObject *target;
NSObject *observer;
// 主要是清理持有的对象
@synchronized (self) {
_block = nil;
// target虽然是unsafe的, 但是这个时候target应该还未释放, 因为在init方法中, 对target的rac_deallocDisposable进行了add self的操作, 如果要释放了, 则会自动调用这方法
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
本质上可以看做一个Disposable数组, 在dispose的时候会把组合进来的Disposable一个个调用dispose.
内部的实现用了C数组和CoreFoundation的数组而不是一个Objc的Array, 原因应该一是性能方面的考虑, 因为CompoundDisposable用的很频繁, 二是会持有这个Disposable, 有一些类型的Disposable是在dealloc的时候要dispose的, 如果持有则会干扰这个行为.
同时, 实现还用了一个魔数长度的固定大小数组, 更多的disposable会额外存储在一个CoreFoundation创建的数组中. 有2个问题:
- 为什么要分为2个部分?
- 为什么这个数字是2?
第一个问题的答案是性能, 用CoreFoundation是比较耗时的, 而直接用一个固定大小的C数组会更快.
第二个问题的答案还是性能, 只不过这个是作者综合测算出来的.
#define RACCompoundDisposableInlineCount 2
基于上面的缘故, 这里实现会看起来比较复杂一点, 但是实际上还是比较好懂的, 看成对数组的操作即可.
- (id)initWithDisposables:(NSArray *)otherDisposables {
self = [self init];
if (self == nil) return nil;
#if RACCompoundDisposableInlineCount
[otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) {
// 前2个存在inline数组中, 也就是C数组
_inlineDisposables[index] = disposable;
// 超过2个的先不管
if (index == RACCompoundDisposableInlineCount - 1) *stop = YES;
}];
#endif
// 大于2个的创建CoreFoundation数组来管理
if (otherDisposables.count > RACCompoundDisposableInlineCount) {
_disposables = RACCreateDisposablesArray();
// 写入数据
CFRange range = CFRangeMake(RACCompoundDisposableInlineCount, (CFIndex)otherDisposables.count - RACCompoundDisposableInlineCount);
CFArrayAppendArray(_disposables, (__bridge CFArrayRef)otherDisposables, range);
}
return self;
}
// dealloc不会自动调用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);
{
// 如果此时已经dispose掉了, 那么也要对该disposable调用dispose
if (_disposed) {
shouldDispose = YES;
} else {
// 主体代码:
// 1. 先找找inline数组里面有没有空位
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
if (_inlineDisposables[i] == nil) {
// 有就赋值, 然后跳到后面去执行
_inlineDisposables[i] = disposable;
goto foundSlot;
}
}
#endif
// 2. 如果已经满额, 就加入到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);
// 在锁外面调用, 防止递归使用CompoundDisposable
if (shouldDispose) [disposable dispose];
}
// remove的操作基本差不多, 主要是一些C函数的使用
- (void)removeDisposable:(RACDisposable *)disposable {
if (disposable == nil) return;
OSSpinLockLock(&_spinLock);
{
if (!_disposed) {
#if RACCompoundDisposableInlineCount
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
// 这里既然已经找到了, 为什么不跳到最后呢? 难道就是为了少写一对大括号么,[手动抠鼻]
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, 显然就会是2个数组的遍历了:
- (void)dispose {
// 1. 把2个数组copy出来到本地
// 这么做一是可以保证线程安全(局部变量是线程安全的)
// 而是可以尽早解开锁
#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数组 调用dispose
for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
[inlineCopy[i] dispose];
}
#endif
if (remainingDisposables == NULL) return;
// 额外的Disposables要传入函数指针来遍历然后调用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];
}
整体来说上面的代码还是比较易懂的, 就是有很多C级别的代码, 很多API都比较底层.
RACSerialDisposable
Signal中说了对RACSerialDisposable调用setDisposable会有额外的一个效果, 旧的值如果已经被dispose了, 那么新的值也会立即dispose掉.
这个类的头文件也比较简单, 一个属性2个方法, 私有属性还有一些线程安全和状态以及辅助操作的声明(属性声明了disposable, 在拓展里面还要写RACDisposable * _disposable是因为实现方法重写了其getter方法--也就是disposable方法, 而在里面又要访问这个值, 为了避免造成递归, 所以需要直接访问, 而不能self.的形式访问).
直接看下这2个getter和setter
- (RACDisposable *)disposable {
// 保证线程安全, 因为有可能会经常变化
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);
// 判断是否已经dispose过
alreadyDisposed = _disposed;
if (!alreadyDisposed) {
// 如果没有, 则把新Disposable赋给属性, 局部变量存储老的Disposable
existingDisposable = _disposable;
_disposable = newDisposable;
}
OSSpinLockUnlock(&_spinLock);
// 如果老的已经dispose过了, 那么新的也直接dispose掉, 返回空
if (alreadyDisposed) {
[newDisposable dispose];
return nil;
}
// 返回老的Disposable
return existingDisposable;
}
dispose方法则没什么特别:
- (void)dispose {
RACDisposable *existingDisposable;
OSSpinLockLock(&_spinLock);
if (!_disposed) {
existingDisposable = _disposable;
_disposed = YES;
_disposable = nil;
}
OSSpinLockUnlock(&_spinLock);
[existingDisposable dispose];
}