ReactiveCocoa信号发送详解

作者: 不会飞的小白 | 来源:发表于2016-12-04 21:00 被阅读299次

    简介

    ReactiveCocoa 是一个重型的 FRP (Functional Reactive Programming 是一种响应变化的编程范式) 框架。内部使用了大量的block。FRP的核心就是信号。
    RACSignal就是信号,是ReactiveCocoa中很重要的一个概念。RACSignal本体是RACStream。信号就是数据流,可以用来传递和绑定。

    以下代码基于V2.5的ReactiveCocoa

    创建RACsignal

    不说废话,先来一张图

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

    通过RACDynamicSignal创建信号,此时传入一个block,这个block的参数是一个遵循RACSubscriber协议的一个变量,同时这个block的返回值是一个RACDisposable类型。

    通过源码分析,看到RACDynamicSignal有一个属性didSubscribe存储了传进来的的block,这个属性将在之后订阅的时候使用。

    这个RACSubscriber的协议,其中定义了几个方法

    @protocol RACSubscriber <NSObject>
    @required
    
    // 发送next需要执行的参数
    - (void)sendNext:(id)value;
    // 发送错误
    - (void)sendError:(NSError *)error;
    // 发送成功
    - (void)sendCompleted;
    // 处理信号,是否释放取消订阅。
    - (void)didSubscribeWithDisposable:(RACCompoundDisposable *)disposable;
    
    @end
    

    创建一个信号

    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        [subscriber sendNext:@"a"];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            
        }];
    }];
    

    订阅

    一个信号通过调用subscribeNext创建一个subscriber进行subscription。

    // RACSignal (Subscription) RACSignal.m
    - (RACDisposable *)subscribeNext:(void (^)(id x))nextBlock {
        NSCParameterAssert(nextBlock != NULL);
        
        RACSubscriber *o = [RACSubscriber subscriberWithNext:nextBlock error:NULL completed:NULL];
        return [self subscribe:o];
    }
    
    // 当前self是RACDynamicSignal所以,使用RACDynamicSignal.m中的subscribe:方法。
    // RACDynamicSignal.m
    - (RACDisposable *)subscribe:(id<RACSubscriber>)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;
    }
    
    1. 源码中创建了一个RACSubscriber来存储nextBlock、error、completed。然后订阅处理subscription。

    2. 这里有一个RACCompoundDisposable,这是一个RACDisposable,只不过RACCompoundDisposable可以存放多个RACDisposable 。当RACCompoundDisposable 执行dispose方法时,它所存放的disposable都会被释放。

    3. 使用RACPassthroughSubscriber将当前的订阅者进行转化,转化为另外一种形式的订阅者。这个订阅者中存储了当前的订阅者,信号、disposable。存储了一个信号的完整处理,并且这个订阅者同样遵循<RACSubscriber>协议。这里可以把RACPassthroughSubscriber当成是订阅者的装饰器(伪装器)。

    4. 使用RACPassthroughSubscriber的目的是将subscirber传递给另一个还没有disposed的subscriber。

      Passes through all events to another subscriber while not disposed.

    5. 当执行self.didSubscribe(subscriber)时siganle存储的block就会被执行。当sendNext:执行时,先执行[RACPassthroughSubscriber sendNext:],然后调用RACPassthroughSubscriber中的subscriber来执行sendNext:

      // 源码
          // 源码
      - (void)sendNext:(id)value {
         if (self.disposable.disposed) return;
      
         if (RACSIGNAL_NEXT_ENABLED()) {
            RACSIGNAL_NEXT(cleanedSignalDescription(self.signal), cleanedDTraceString(self.innerSubscriber.description), cleanedDTraceString([value description]));
         }
      
         [self.innerSubscriber sendNext:value];
      

    }
    继续执行addDisposable,此时会将RACCompoundDisposable```释放。

    ```objc
    // 源码
    - (void)addDisposable:(RACDisposable *)disposable {
    NSCParameterAssert(disposable != self);
    if (disposable == nil || disposable.disposed) return;
    
    BOOL shouldDispose = NO;
    
    OSSpinLockLock(&_spinLock);
    {
        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
        }
    }
    OSSpinLockUnlock(&_spinLock);
    
    // Performed outside of the lock in case the compound disposable is used
    // recursively.
    // 会在此处释放。
    if (shouldDispose) [disposable dispose];
    

    }

    
    6. 源码中可以看出,订阅一个信号,返回的是一个RACDisposable,作为一个返回值返回到外部,我们可以在外部对其取消这个订阅。
    
    ###总结
    ```objc
    // part 1.
    RACSignal *aSignal = [RACSignal createSignal:^RACDisposable *(id<RACSubscriber> subscriber) {
        // 此处subscriber为转换后的subscriber
        // part 5.
       [subscriber sendNext:@"abc"];
       [subscriber sendCompleted];
        
       // part 6.
       return [RACDisposable disposableWithBlock:^{
           NSLog(@"disposable");
       }];
    }];
    
    // part 2.
    RACDisposable *adisposable = [aSignal subscribeNext:^(id x) {
       NSLog(@"~~~~~~~~~~~  %@",x);
    }];
    
    1. 调用createSignal:创建一个信号。存储当前的block到didSubscribe这个block中。
    2. 调用subscribeNext:订阅信号。创建一个subscriber来subscription。在subscriber中存储nextBlock,errorBlock,completeBlock三个block。
    3. 当前的订阅通过转换,成为RACPassthroughSubscriber,这个subscriber中有三个重要的属性分别是当前订阅的subscriber,当前的signal和RACCompoundDisposable。
    4. RACDynamicSignal执行didSubscribe(RACPassthroughSubscriber)这个block。执行RACPassthroughSubscriber中的sendNext:, sendError:, sendCompeleted
    5. RACPassthroughSubscriber中通过判断当前的disposable的状态来判断是否告诉subscriber调用相应的sendNext:等。
    6. 调用dispose方法,完成整个过程。

    用一张图来来表示整个过程


    ReactiveCocoa.jpg

    引用

    ReactiveCocoa gitHub

    美团点评技术团队RACSignal的Subscription深入分析

    iOS ReactiveCocoa详解

    写在最后

    第一篇ReactiveCocoa的文章,写的不好,如有写的不对的地方,欢迎指正,共同进步。谢谢!!!

    相关文章

      网友评论

        本文标题:ReactiveCocoa信号发送详解

        本文链接:https://www.haomeiwen.com/subject/odnhmttx.html