iOS-RAC综述

上一篇我们探索了RAC的核心流程就是:

  • 创建信号
  • 订阅信号
  • 订阅者发送信号
  • 销毁

那么我们根据这些操作来看看RAC的核心类以及具体实现,主要就是信号、订阅、销毁这3个点。

RACSignal

RACSiganl,信号类,是抽象类RACStream的子类。在RAC中,万物皆信号,只有有了信号,才会有的一系列操作。一般表示将来有数据传递,只要有数据改变,信号内部接收到数据,就会马上发出数据。但是它本身不具备发送信号的能力,而是交给内部一个订阅者去发出。

+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe {
    return [RACDynamicSignal createSignal:didSubscribe];
}

而最终的订阅方法的实现是由RACDynamicSignal来完成的。该类有2个方法,一个就是创建信号,保存信号创建的回调;另一个就是执行订阅方法的时候调用信号创建保存的block,返回销毁者。

+ (RACSignal *)createSignal:(RACDisposable * (^)(id subscriber))didSubscribe {
    RACDynamicSignal *signal = [[self alloc] init];
    signal->_didSubscribe = [didSubscribe copy];
    return [signal setNameWithFormat:@"+createSignal:"];
}


- (RACDisposable *)subscribe:(id)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];

    if (self.didSubscribe != NULL) {
        RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
            RACDisposable *innerDisposable = self.didSubscribe(subscriber);
            [disposable addDisposable:innerDisposable];
        }];

        [disposable addDisposable:schedulingDisposable];
    }
    
    return disposable;
}

RACPassthroughSubscriber

核心订阅类RACPassthroughSubscriber实现了一个协议RACSubscriber,实现了该协议就有订阅信号,接收值处理值的能力。

- (instancetype)initWithSubscriber:(id)subscriber signal:(RACSignal *)signal disposable:(RACCompoundDisposable *)disposable {
    NSCParameterAssert(subscriber != nil);

    self = [super init];

    _innerSubscriber = subscriber;
    _signal = signal;
    _disposable = disposable;

    [self.innerSubscriber didSubscribeWithDisposable:self.disposable];
    return self;
}
  • subscriber:核心订阅者
  • signal:信号
  • disposable:销毁者

那我们再来看看, RACSubscriber这个协议都定义了那些方法

  1. 保存nextBlock、错误信息、完成信息。
+ (instancetype)subscriberWithNext:(void (^)(id x))next error:(void (^)(NSError *error))error completed:(void (^)(void))completed {
    RACSubscriber *subscriber = [[self alloc] init];

    subscriber->_next = [next copy];
    subscriber->_error = [error copy];
    subscriber->_completed = [completed copy];

    return subscriber;
}
  1. 发送正常的信号,然后执行数据的回调。
- (void)sendNext:(id)value {
    @synchronized (self) {
        void (^nextBlock)(id) = [self.next copy];
        if (nextBlock == nil) return;

        nextBlock(value);
    }
}
  1. 发送错误,会销毁信号,然后回调错误,以后再也不接收这个信号的变化了。
- (void)sendError:(NSError *)e {
    @synchronized (self) {
        void (^errorBlock)(NSError *) = [self.error copy];
        [self.disposable dispose];

        if (errorBlock == nil) return;
        errorBlock(e);
    }
}
  1. 发送完成信号,会销毁信号,然后回调完成的操作,同样,以后再也不接收这个信号的变化了。
- (void)sendCompleted {
    @synchronized (self) {
        void (^completedBlock)(void) = [self.completed copy];
        [self.disposable dispose];

        if (completedBlock == nil) return;
        completedBlock();
    }
}

可以看到sendErrorsendCompleted是在方法里就会销毁,那么sendNext是什么时候销毁呢?就是调用者销毁的时候,也就是我们所说的self或者viewController销毁的时候。就会调用到RACSubscriber重写的dealloc方法。

- (void)dealloc {
    [self.disposable dispose];
}

RACScheduler

Schedulers are used to control when and where work is performed.

调度者,用于控制工作何时何地执行。其实,它就是对GCD的封装。

当我们在- (RACDisposable *)subscribe:(id)subscriber方法中调用schedule方法的时候,会判断是否有currentScheduler,如果有执行schedule中的block,没有的话就使用自己定义的backgroundScheduler,进行处理block

- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);

    if (RACScheduler.currentScheduler == nil) return [self.backgroundScheduler schedule:block];

    block();
    return nil;
}

会先从threadDictionary里面获取RACScheduler,如果获取的值不为nil就将其值返回,用来调用信号的处理。如果为空的话,再来判断当前的任务是否在主队列或者主线程,如果是的话就返回自己封装的GCD主队列用来调用。

+ (RACScheduler *)currentScheduler {
    RACScheduler *scheduler = NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey];
    if (scheduler != nil) return scheduler;
    if ([self.class isOnMainThread]) return RACScheduler.mainThreadScheduler;

    return nil;
}

+ (BOOL)isOnMainThread {
    return [NSOperationQueue.currentQueue isEqual:NSOperationQueue.mainQueue] || [NSThread isMainThread];
}

+ (RACScheduler *)mainThreadScheduler {
    static dispatch_once_t onceToken;
    static RACScheduler *mainThreadScheduler;
    dispatch_once(&onceToken, ^{
        mainThreadScheduler = [[RACTargetQueueScheduler alloc] initWithName:@"org.reactivecocoa.ReactiveObjC.RACScheduler.mainThreadScheduler" targetQueue:dispatch_get_main_queue()];
    });
    
    return mainThreadScheduler;
}

_backgroundScheduler其实也是一个默认优先级的全局串行队列,它是由RACTargetQueueScheduler生成的实例。

RACTargetQueueScheduler, A scheduler that enqueues blocks on a private serial queue, targeting an arbitrary GCD queue.

RACTargetQueueScheduler是在任意的GCD的线程中创建一个串行队列,然后将这些待处理的block都放在这个串行对劣质,让调度者处理的block能够同步执行,也就是让信号的任务同步执行。

_backgroundScheduler = [RACScheduler scheduler];

+ (RACScheduler *)scheduler {
    return [self schedulerWithPriority:RACSchedulerPriorityDefault];
}

+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority {
    return [self schedulerWithPriority:priority name:@"org.reactivecocoa.ReactiveObjC.RACScheduler.backgroundScheduler"];
}

// 创建一个全局的并发队列
+ (RACScheduler *)schedulerWithPriority:(RACSchedulerPriority)priority name:(NSString *)name {
    return [[RACTargetQueueScheduler alloc] initWithName:name targetQueue:dispatch_get_global_queue(priority, 0)];
}

- (instancetype)initWithName:(NSString *)name targetQueue:(dispatch_queue_t)targetQueue {
    NSCParameterAssert(targetQueue != NULL);

    if (name == nil) {
        name = [NSString stringWithFormat:@"org.reactivecocoa.ReactiveObjC.RACTargetQueueScheduler(%s)", dispatch_queue_get_label(targetQueue)];
    }

    // 此处使用串行队列的原因就是想要信号一个一个的处理
    dispatch_queue_t queue = dispatch_queue_create(name.UTF8String, DISPATCH_QUEUE_SERIAL);
    if (queue == NULL) return nil;

    // 防止信号并发处理
    dispatch_set_target_queue(queue, targetQueue);

    return [super initWithName:name queue:queue];
}

全局串行队列调度处理的方式如下:

- (RACDisposable *)schedule:(void (^)(void))block {
    NSCParameterAssert(block != NULL);

    RACDisposable *disposable = [[RACDisposable alloc] init];

    dispatch_async(self.queue, ^{
        if (disposable.disposed) return;
        [self performAsCurrentScheduler:block];
    });

    return disposable;
}

- (void)performAsCurrentScheduler:(void (^)(void))block {
    NSCParameterAssert(block != NULL);

    // 获取当前的调度者 
    RACScheduler *previousScheduler = RACScheduler.currentScheduler;
    NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = self;

    // 先执行调度的block
    autoreleasepool {
        block();
    }

    if (previousScheduler != nil) {
        // 如果不是空的 放入threadDictionary
        NSThread.currentThread.threadDictionary[RACSchedulerCurrentSchedulerKey] = previousScheduler;
    } else {
        // 如果是空的就移除threadDictionary中对应的值
        // 执行下一次schedule操作的又会进入一次新的判断
        [NSThread.currentThread.threadDictionary removeObjectForKey:RACSchedulerCurrentSchedulerKey];
    }
}

验证一下:

  1. 主线程执行调度
主线程调度.png
  1. 子线程执行调度
子线程调度.png

可以看出当在主线程中使用信号的时候,调度者是把主线程的中的信号任务加入到主线程串行队列中执行,而在子线程中使用信号的时候,调度者会自己创建一个子线程,并把任务都加入到自己创建的这个子线程同步队列中执行。整个流程大致如下:

RACScheduler.png

RACDisposable & RACCompoundDisposable

RACDisposable,销毁者,取消订阅,销毁订阅信号操作中间生成的一些辅助销毁对象。
RACCompoundDisposable继承自RACDisposable,它和RACDisposable的区别是RACDisposable是单个销毁者,RACCompoundDisposable是销毁者集合,它管理着一个或者多个RACDisposable

- (instancetype)initWithBlock:(void (^)(void))block {
    NSCParameterAssert(block != nil);

    self = [super init];
    
    // 保存销毁后续操作的block
    _disposeBlock = (void *)CFBridgingRetain([block copy]); 
    OSMemoryBarrier();

    return self;
}

+ (instancetype)disposableWithBlock:(void (^)(void))block {
    return [[self alloc] initWithBlock:block];
}

- (void)dealloc {
    if (_disposeBlock == NULL || _disposeBlock == (__bridge void *)self) return;

    CFRelease(_disposeBlock);
    _disposeBlock = NULL;
}

- (void)dispose {
    void (^disposeBlock)(void) = NULL;

    while (YES) {
        void *blockPtr = _disposeBlock;
        // 防止多线程操作引发的错误 
        if (OSAtomicCompareAndSwapPtrBarrier(blockPtr, NULL, &_disposeBlock)) {
            if (blockPtr != (__bridge void *)self) {
                disposeBlock = CFBridgingRelease(blockPtr);
            }
            break;
        }
    }
    
    // 执行销毁后续的block
    if (disposeBlock != nil) disposeBlock();
}

当订阅者调用dealloc方法的时候执行[self.disposable dispose],由于销毁者都被RACCompoundDisposable管理,就会调用[RACCompoundDisposable dispose],在这个方法中,遍历管理的销毁者,找到对应需要销毁的,然后调用[RACDisposable dispose]进行销毁。

+ (instancetype)compoundDisposable {
    return [[self alloc] initWithDisposables:nil];
}

+ (instancetype)compoundDisposableWithDisposables:(NSArray *)disposables {
    return [[self alloc] initWithDisposables:disposables];
}

- (instancetype)init {
    self = [super init];
    const int result __attribute__((unused)) = pthread_mutex_init(&_mutex, NULL);
    return self;
}

- (instancetype)initWithDisposables:(NSArray *)otherDisposables {
    self = [self init];

    // 将所有disposable保存到_inlineDisposables
#if RACCompoundDisposableInlineCount
    [otherDisposables enumerateObjectsUsingBlock:^(RACDisposable *disposable, NSUInteger index, BOOL *stop) {
        self->_inlineDisposables[index] = disposable;
        if (index == RACCompoundDisposableInlineCount - 1) *stop = YES;
    }];
#endif
    // 相对应的添加操作
    if (otherDisposables.count > RACCompoundDisposableInlineCount) {
        _disposables = RACCreateDisposablesArray();

        CFRange range = CFRangeMake(RACCompoundDisposableInlineCount, (CFIndex)otherDisposables.count - RACCompoundDisposableInlineCount);
            CFArrayAppendArray(_disposables, (__bridge CFArrayRef)otherDisposables, range);
    }
    return self;
}

- (instancetype)initWithBlock:(void (^)(void))block {
    RACDisposable *disposable = [RACDisposable disposableWithBlock:block];
    return [self initWithDisposables:@[ disposable ]];
}

// 向RACCompoundDisposable管理集合中添加 RACDisposable
// 将disposable添加到_inlineDisposables
// 如果_inlineDisposables满了就添加到_disposables
- (void)addDisposable:(RACDisposable *)disposable {
    NSCParameterAssert(disposable != self);
    if (disposable == nil || disposable.disposed) return;

    BOOL shouldDispose = NO;

    pthread_mutex_lock(&_mutex);
    {
        if (_disposed) {
            shouldDispose = YES;
        } else {
        #if RACCompoundDisposableInlineCount
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                if (_inlineDisposables[i] == nil) {
                    _inlineDisposables[i] = disposable;
                    goto foundSlot;
                }
            }
        #endif

            if (_disposables == NULL) 
                _disposables = RACCreateDisposablesArray();
            CFArrayAppendValue(_disposables, (__bridge void *)disposable);

            if (RACCOMPOUNDDISPOSABLE_ADDED_ENABLED()) {
                RACCOMPOUNDDISPOSABLE_ADDED(self.description.UTF8String, disposable.description.UTF8String, CFArrayGetCount(_disposables) + RACCompoundDisposableInlineCount);
            }

    #if RACCompoundDisposableInlineCount
        foundSlot:;
    #endif
        }
        
    }
    pthread_mutex_unlock(&_mutex);

    if (shouldDispose) [disposable dispose];
}

// 从RACCompoundDisposable管理集合中移除 RACDisposable 
// 删除_inlineDisposables对应的disposable
- (void)removeDisposable:(RACDisposable *)disposable {
    if (disposable == nil) return;

    pthread_mutex_lock(&_mutex);
    {
        if (!_disposed) {
        // 移除_inlineDisposables中的RACDisposable
        #if RACCompoundDisposableInlineCount
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                if (_inlineDisposables[i] == disposable)
                    _inlineDisposables[i] = nil;
            }
        #endif
            
            // 移除_disposables中的RACDisposable
            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);
                }
            }
        }
    }
    pthread_mutex_unlock(&_mutex);
}

// 对_disposables中的RACDisposable进行销毁
static void disposeEach(const void *value, void *context) {
    RACDisposable *disposable = (__bridge id)value;
    [disposable dispose];
}

// 遍历_inlineDisposables中的RACDisposable,进行销毁
// 如果_disposables中存在RACDisposable,也需要进行遍历,销毁
// 销毁的操作就是将原来的值置为nil
- (void)dispose {
    #if RACCompoundDisposableInlineCount
        RACDisposable *inlineCopy[RACCompoundDisposableInlineCount];
    #endif

    CFArrayRef remainingDisposables = NULL;

    pthread_mutex_lock(&_mutex);
    {
        _disposed = YES;

        #if RACCompoundDisposableInlineCount
            for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
                inlineCopy[i] = _inlineDisposables[i];
                _inlineDisposables[i] = nil;
            }
        #endif

        remainingDisposables = _disposables;
        _disposables = NULL;
    }
    pthread_mutex_unlock(&_mutex);
    
    
    // 对_inlineDisposables中的RACDisposable 进行销毁
    #if RACCompoundDisposableInlineCount
    for (unsigned i = 0; i < RACCompoundDisposableInlineCount; i++) {
        [inlineCopy[i] dispose];
    }
    #endif

    if (remainingDisposables == NULL) return;

    CFIndex count = CFArrayGetCount(remainingDisposables);
    CFArrayApplyFunction(remainingDisposables, CFRangeMake(0, count), &disposeEach, NULL);
    CFRelease(remainingDisposables);
}

#define RACCompoundDisposableInlineCount 2

RACCompoundDisposable通过2种方式对RACDisposable实例进行管理:

  • _inlineDisposablesRACDisposable *_inlineDisposables[RACCompoundDisposableInlineCount],这是一种快捷方式,但是只能添加2个,一旦满了,就需要创建_disposables这个数组来存储。对_inlineDisposables的操作需要加锁。
  • _disposablesCFMutableArrayRef _disposables,这个数组是作为一个备用数组,当_inlineDisposables存满了就需要使用这个数组来存储RACDisposable。操作需要加锁。当_disposables也存满了就需要将保存的disposable销毁。

在上述例子,我们在销毁信号的地方设置一个断点,查看一下堆栈信息:

销毁者流程.png

这也验证了我们上述的流程。

RACObserve

RACObserve是对KVO的封装,下面我们来看看其具体实现。

#define RACObserve(TARGET, KEYPATH) _RACObserve(TARGET, KEYPATH)

#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 {
    return [[[self
        rac_valuesAndChangesForKeyPath:keyPath options:NSKeyValueObservingOptionInitial observer:observer]
        map:^(RACTuple *value) {
            return value[0];
    }]
    setNameWithFormat:@"RACObserve(%@, %@)", RACDescription(self), keyPath];
}

- (RACSignal *)rac_valuesAndChangesForKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver {
    NSObject *strongObserver = weakObserver;
    keyPath = [keyPath copy];
    
    __weak NSObject *weakSelf = self;
    
    // target的销毁信号,不再订阅信号
    RACSignal *deallocSignal = [[RACSignal
        zip:@[
            self.rac_willDeallocSignal,
            strongObserver.rac_willDeallocSignal ?: [RACSignal never]
        ]]
        doCompleted:^{
            ......
        }];

    return [[[RACSignal
        createSignal:^ RACDisposable * (id subscriber) {
            
            ......
            // 观察者销毁 订阅者也发送完成信号
            if (self == nil) {
                [subscriber sendCompleted];
                return nil; 
            }

            return [self rac_observeKeyPath:keyPath options:options observer:observer block:^(id value, NSDictionary *change, BOOL causedByDealloc, BOOL affectedOnlyLastComponent) {
                // 如果KVO检测到被观察者发生变化,则通过订阅者发送信号数据
                [subscriber sendNext:RACTuplePack(value, change)];
            }];
        }]
        // 销毁信号之后不再订阅信号
        takeUntil:deallocSignal]];
}

- (RACDisposable *)rac_observeKeyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options observer:(__weak NSObject *)weakObserver block:(void (^)(id, NSDictionary *, BOOL, BOOL))block {
    ......

    keyPath = [keyPath copy];

    NSObject *strongObserver = weakObserver;
    
    // 对keyPath的处理
    NSArray *keyPathComponents = keyPath.rac_keyPathComponents;
    BOOL keyPathHasOneComponent = (keyPathComponents.count == 1);
    NSString *keyPathHead = keyPathComponents[0];
    NSString *keyPathTail = keyPath.rac_keyPathByDeletingFirstKeyPathComponent;

    // 初始化销毁者管理集合 
    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];

    BOOL shouldAddDeallocObserver = NO;

    // 获取观察者的属性 这也就是为什么我们能在RACObserve()里面获取到响应属性的原因
    objc_property_t property = class_getProperty(object_getClass(self), keyPathHead.UTF8String);
    if (property != NULL) {
        rac_propertyAttributes *attributes = rac_copyPropertyAttributes(property);
        if (attributes != NULL) {
            shouldAddDeallocObserver = isObject && isWeak && !isBlock && !isProtocol;
        }
    }

    // dealloc观察者订阅信号的销毁操作
    void (^addDeallocObserverToPropertyValue)(NSObject *) = ^(NSObject *value) {
        .......
        RACDisposable *deallocDisposable = [RACDisposable disposableWithBlock:^{
            block(nil, change, YES, keyPathHasOneComponent);
        }];

        [valueDisposable addDisposable:deallocDisposable];
        [firstComponentDisposable() addDisposable:[RACDisposable disposableWithBlock:^{
            [valueDisposable removeDisposable:deallocDisposable];
        }]];
    };

    // 将回调块添加到值的dealloc操作中,把清理回调的逻辑添加到销毁者
    void (^addObserverToValue)(NSObject *) = ^(NSObject *value) {
        RACDisposable *observerDisposable = [value rac_observeKeyPath:keyPathTail options:(options & ~NSKeyValueObservingOptionInitial) observer:weakObserver block:block];
            [firstComponentDisposable() addDisposable:observerDisposable];
    };

    NSKeyValueObservingOptions trampolineOptions = (options | NSKeyValueObservingOptionPrior) & ~NSKeyValueObservingOptionInitial;
    
    // 将观察的属性封装起来 进行观察
    // RACKVOTrampoline 是KVO的观察者 一旦被dispose 观察就会停止
    RACKVOTrampoline *trampoline = [[RACKVOTrampoline alloc] initWithTarget:self observer:strongObserver keyPath:keyPathHead options:trampolineOptions block:^(id trampolineTarget, id trampolineObserver, NSDictionary *change) {
            // 观察者发生变化的回调
            // 之后再通过sendNext的方式传给订阅者
            ......
            block([value valueForKeyPath:keyPathTail], change, NO, keyPathHasOneComponent);
            ......
    }];
    
    // 当销毁trampoline的时候就停止KVO观察
    [disposable addDisposable:trampoline];
    
    // 如果需要的话 返回初始化的值
    block(initialValue, initialChange, NO, keyPathHasOneComponent);

    ......
    
    // 销毁对应的观察
    return [RACDisposable disposableWithBlock:^{
        [disposable dispose];
        [observerDisposable removeDisposable:disposable];
        [selfDisposable removeDisposable:disposable];
    }];
}

// RACKVOTrampoline继承自RACDisposable,是一个KVO观察
// 将被观察者封装起来
- (instancetype)initWithTarget:(__weak NSObject *)target observer:(__weak NSObject *)observer keyPath:(NSString *)keyPath options:(NSKeyValueObservingOptions)options block:(RACKVOBlock)block {

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

    self = [super init];

    // 保存观察的相关信息:keyPath、回调block、被观察者、观察者
    _keyPath = [keyPath copy];
    _block = [block copy];
    _weakTarget = target;
    _unsafeTarget = strongTarget;
    _observer = observer;

    // 使用中间代理层来响应KVO
    // strongTarget 被观察对象
    // RACKVOProxy.sharedProxy 观察者
    // 在RACKVOProxy.sharedP内部维护一张NSMapTable 把所有的观察者都存在这个表里
    [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,被观察者变化的回调
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
    RACKVOBlock block;
    id observer;
    id target;

    @synchronized (self) {
        block = self.block;
        observer = self.observer;
        target = self.weakTarget;
    }

    if (block == nil || target == nil) return;

    // 观察到被观察者变化的回调block
    block(target, observer, change);
}

- (void)dispose {
    NSObject *target;
    NSObject *observer;

    @synchronized (self) {
        _block = nil;
        target = self.unsafeTarget;
        observer = self.observer;

        _unsafeTarget = nil;
        _observer = nil;
    }

    [target.rac_deallocDisposable removeDisposable:self];
    [observer.rac_deallocDisposable removeDisposable:self];
    
    // 以下两步就确定了RACKVO不需要手动移除观察者
    // 移除中间层的观察
    [target removeObserver:RACKVOProxy.sharedProxy forKeyPath:self.keyPath context:(__bridge void *)self];
    // 中间层移除观察者
    [RACKVOProxy.sharedProxy removeObserver:self forContext:(__bridge void *)self];
}

总结一下:

  • RACObserve是封装的一个宏定义,这个宏定义的实现在NSObject的一个名为RACPropertySubscribing的分类,
  • RACPropertySubscribing中主要的处理:
    • 当收到释放订阅观察的信号就不再订阅、
    • 当前类被销毁的时候,订阅者发送完成的信号
  • 进入NSObjectRACKVOWrapper分类中,主要处理如下:
    • keyPath的处理,比如二级路由等
    • 初始化RACCompoundDisposable管理销毁者
    • 获取观察者的属性
    • 处理一些关于dealloc的销毁操作
  • 进入RACKVOTrampoline这个类:
    • 包装观察需要的相关属性
    • 使用中间层RACKVOProxy来观察被观察的对象,而不是直接使用观察者,将观察者保存在RACKVOProxy
    • RACKVOTrampoline被释放的时候,移除观察者
    • 回调给外界观察者发生的变化
  • RACKVOProxy:中间层,充当观察者
    • 维护一张表NSMapTable来保存原来的观察者
    • 响应系统被观察者发生变化的回调

被观察者的变化则是通过订阅者发送给外界:

[subscriber sendNext:RACTuplePack(value, change)]

移除观察者的流程则是当观察者被销毁的时候,就会销毁相关的临时变量,也就是观察的销毁者等,这样就会调用到RACKVOTrampoline这个类的dispose方法,移除观察者。

RACObserve.png

RACSubject

RACSubject可以看做是一种可以手动控制发送next, completed, and error的信号,对桥接RAC和非RAC很有帮助。它RACSignal的子类,还实现了RACSubscriber协议。
它有以下特点:

  • 能够手动发送事件
  • 能够订阅信号
RACSubject.png

那么,它是如何做到又能发送信号,又能订阅信号的呢?我们来看看它的内部实现。

@property (nonatomic, strong, readonly) NSMutableArray *subscribers;
@property (nonatomic, strong, readonly) RACCompoundDisposable *disposable;

+ (instancetype)subject {
    return [[self alloc] init];
}

- (instancetype)init {
    self = [super init];
    if (self == nil) return nil;

    _disposable = [RACCompoundDisposable compoundDisposable];
    _subscribers = [[NSMutableArray alloc] initWithCapacity:1];
    
    return self;
}

它的内部维护了一个销毁者集合和一个订阅者数组。这个订阅者的数组就是实现订阅的关键。

外部调用订阅方法的时候,就会把生成的订阅者存放在_subscribers这个数组里面。

- (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
    NSCParameterAssert(nextBlock != NULL);
    
    RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
    return [self subscribe:o];
}

- (RACDisposable *)subscribe:(id)subscriber {
    NSCParameterAssert(subscriber != nil);

    RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
    // 生成订阅者
    subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    
    // 添加订阅者 保存
    NSMutableArray *subscribers = self.subscribers;
    @synchronized (subscribers) {
        [subscribers addObject:subscriber];
    }
    
    // 销毁者销毁订阅者
    [disposable addDisposable:[RACDisposable disposableWithBlock:^{
        @synchronized (subscribers) {
            NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id obj, NSUInteger index, BOOL *stop) {
                return obj == subscriber;
            }];

            if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
        }
    }]];

    return disposable;
}

当外部调用sendNext发送信号的方法时,它会遍历之前存放的_subscribers数组,一一回调执行每个订阅者的sendNext方法。

- (void)sendNext:(id)value {
    [self enumerateSubscribersUsingBlock:^(id subscriber) {
        [subscriber sendNext:value];
    }];
}

- (void)enumerateSubscribersUsingBlock:(void (^)(id subscriber))block {
    NSArray *subscribers;
    @synchronized (self.subscribers) {
        subscribers = [self.subscribers copy];
    }
    
    // 遍历订阅者列表 回调
    for (id subscriber in subscribers) {
        block(subscriber);
    }
}

由于RACSubject响应信号的时候时候是遍历订阅者,一一响应,那么我们可以得出多个订阅者订阅同一个信号,响应的时候不需要多次发送信号消息。

multisubjectTest.png

RACMulticastConnection

RACMulticastConnection,多播信号,用于将一个信号发送给多个订阅者。通俗的说,就是多个订阅者都订阅了一个信号,当这个信号发出消息的时候,每个订阅者都会收到,而不需要单独的给每个订阅者都发送一次消息。调用了-[RACMulticastConnection connect]方法才会开始订阅多播信号。RACMulticastConnection不应该手动创建,而是通过-[RACSignal publish]或者-[RACSignal multicast:]方法创建。

- (RACMulticastConnection *)publish {
    // 在内部会生成一个手动信号
    RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
    RACMulticastConnection *connection = [self multicast:subject];
    return connection;
}

- (RACMulticastConnection *)multicast:(RACSubject *)subject {
    [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
    RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
    return connection;
}

- (instancetype)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
    NSCParameterAssert(source != nil);
    NSCParameterAssert(subject != nil);

    self = [super init];
    
    _sourceSignal = source; // 原信号
    _serialDisposable = [[RACSerialDisposable alloc] init];
    _signal = subject; // 新建的手动信号
    
    return self;
}

我们再来看看RACMulticastConnectionRACSignal的区别:

RACMulticastConnection发送:

RACMulticastConnection.png

RACSignal发送:

RACSignal多次发送.png

同一个信号给多个订阅者发送信息的时候,RACMulticastConnection只需要发送一次,所有订阅者都会响应;而RACSignal则需要给每个订阅者都发送一次。例子中的connection.signal其实已经是内部创建的RACSubject,而RACSubject订阅信号的时候是把订阅者都放在一个数组里,响应信号的时候则是遍历这个数组挨个响应,就不需要我们一一发信号了。

RACCommand

RACCommand是响应某些动作(通常与UI相关)而触发的信号。在用于与UIKit组件进行交互时,RACCommand能够帮助我们更快的处理并且响应任务,减少编码以及工程的复杂度。

我们先来看一个RACCommand的例子:

RACCommand.png

executionSignals中发送了新的信号时,switchToLatest方法返回的信号都会订阅这个最新的信号,这里也就保证了每次都会打印出最新的信号中的值。executing用来监听是否正在执行中,当执行开始后会置为1、执行结束之后置为0。

那么RACCommand是如何实现订阅信号的呢?在其内部维护了一个RACSubject *addedExecutionSignalsSubject的对象,通过这个对象,它可以将信号的变化发给订阅者。

- (RACSignal *)execute:(id)input {
    ......
    RACSignal *signal = self.signalBlock(input);

    // 多播信号发送信号给订阅者
    RACMulticastConnection *connection = [[signal
        subscribeOn:RACScheduler.mainThreadScheduler]
        multicast:[RACReplaySubject subject]];
    
    [self.addedExecutionSignalsSubject sendNext:connection.signal];

    [connection connect];
    return [connection.signal setNameWithFormat:@"%@ -execute: %@", self, RACDescription(input)];
}

RACCommand在初始化的时候维护了很多关于信号的状态,而这些状态可以帮助我们判断信号的情况。

- (instancetype)initWithSignalBlock:(RACSignal * (^)(id input))signalBlock {
    return [self initWithEnabled:nil signalBlock:signalBlock];
}

- (instancetype)initWithEnabled:(RACSignal *)enabledSignal signalBlock:(RACSignal * (^)(id input))signalBlock {
    NSCParameterAssert(signalBlock != nil);

    self = [super init];
    
    _addedExecutionSignalsSubject = [RACSubject new];
    _allowsConcurrentExecutionSubject = [RACSubject new];
    _signalBlock = [signalBlock copy];  
    
    // 包含信号的信号
    // 在每次执行 -execute: 方法时,最终都会向 executionSignals 中传入一个最新的信号
    _executionSignals = ......;
    
    // errorsConnection 发生错误的多播信号
    RACMulticastConnection *errorsConnection = ......;

    // immediateExecuting 是一个用于表示当前是否有任务执行的信号
    RACSignal *immediateExecuting = ......;

    // _executing是否正在执行
    _executing = ......;
    
    // moreExecutionsAllowed 是否允许更多操作执行的信号
    RACSignal *moreExecutionsAllowed = ......;
    
    // 在每次原信号发送消息时都会重新计算
    _immediateEnabled = ......;
    
    // 是否可以再次执行
    _enabled = ......;

    return self;
}

总结

  • RACPassthroughSubscriber类,就是用来订阅信号、发送信号任务的。
  • RACScheduler类,封装GCD,让信号任务同步执行。
  • RACDisposable类,销毁者,取消订阅,销毁订阅信号操作中间生成的一些辅助销毁对象。
  • RACCompoundDisposable继承自RACDisposable,是销毁者集合,它通过_inlineDisposables_disposables管理着一个或者多个RACDisposable
  • RACObserve:封装系统的KVO,使用RACKVOTrampoline将观察的相关信息封装起来,使用中间层RACKVOProxy作为观察者来进行观察,将原来的观察者维护在NSMapTable表中,当观察到对象发生变化时,RACKVOTrampoline通过回调通知RACKVOWrapper类,然后以发送信号的方式,通知外界。移除观察也在RACKVOTrampoline中进行处理。
  • RACSubject:订阅信号的时候,将生成的RACPassthroughSubscriber订阅者存在_subscribers数组里;发送信号的时候,遍历数组,一一发放。
  • RACMulticastConnection,多播信号,用于将信号发送给多个订阅者。与RACSignal不同的是,它只需要发送一次,所有订阅者都会收到。
  • RACCommand用于表示事件的执行,多用于响应UI上的某些动作。

你可能感兴趣的:(iOS-RAC综述)