美文网首页MVVM+RAC
RACSignal操作的核心bind实现分析

RACSignal操作的核心bind实现分析

作者: 月影随风_ | 来源:发表于2018-01-13 20:06 被阅读67次

先来说说bind函数的作用:

  • 会订阅原始的信号。
  • 任何时刻原始信号发送一个值,都会绑定的block转换一次。
  • 一旦绑定的block转换了值变成信号,就立即订阅,并把值发给订阅者subscriber。
  • 一旦绑定的block要终止绑定,原始的信号就complete。
  • 当所有的信号都complete,发送completed信号给订阅者subscriber。
  • 如果中途信号出现了任何error,都要把这个错误发送给subscriber
// 创建源信号
// 创建了一个 RACDynamicSignal 类型的信号,并将传入的代码块保存起来,留待以后调用。
1. RACSignal *signal = [RACSignal createSignal:
                         ^RACDisposable *(id<RACSubscriber> subscriber)
    {
        //block1
8.      [subscriber sendNext:@1];
        [subscriber sendNext:@2];
        [subscriber sendNext:@3];
        [subscriber sendCompleted];
        return [RACDisposable disposableWithBlock:^{
            NSLog(@"signal dispose");
        }];
    }];
    
    //绑定源信号,生成绑定信号
    //bind操作实际上是直接生成绑定信号并返回,并且在生成绑定信号传入的didSubscriber block代码块中,保存了bind传入的block,初始化了信号数组,并且订阅了源信号,针对源信号发送信号的流程做了一些处理。(此时未执行,订阅才执行)
2.  RACSignal *bindSignal = [signal bind:^RACStreamBindBlock{
        // block 2
6.      return ^RACSignal *(NSNumber *value, BOOL *stop){
            // block 3
10.         value = @(value.integerValue * 2);
            return [RACSignal return:value];
        };
    }];
    //订阅绑定信号
    //订阅绑定信号就是保存了nextBlock,并且创建订阅者,实现信号的didSubscriber block代码块。
4.  [bindSignal subscribeNext:^(id x) {
        // block 4
14.     NSLog(@"subscribe value = %@", x);
    }];
- (RACSignal *)bind:(RACStreamBindBlock (^)(void))block {
    // block 5
3.    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
        // block 6
5.      RACStreamBindBlock bindingBlock = block();
        NSMutableArray *signals = [NSMutableArray arrayWithObject:self];
        
        void (^completeSignal)(RACSignal *, RACDisposable *) = ^(RACSignal *signal, RACDisposable *finishedDisposable) {
15.     // block 7
        };
        
        void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
            // block 8
12.         RACDisposable *disposable = [signal subscribeNext:^(id x) {
            // block 9
13.             [subscriber sendNext:x];
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
14.                 completeSignal(signal, selfDisposable);
                }
            }];
        };
        
        @autoreleasepool {
7.          RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
                // block 10
9.           id signal = bindingBlock(x, &stop);
                
                @autoreleasepool {
11.                 if (signal != nil) addSignal(signal);
                    if (signal == nil || stop) {
                        [selfDisposable dispose];
                        completeSignal(self, selfDisposable);
                    }
                }
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(self, selfDisposable);
                }
            }];
        }
        return compoundDisposable;
    }] ;
}

bind底层实现分析:

  • 序号1 .先创建信号signal,内部创建RACDynamicSignal,属性didSubscribeblock1 copy保存起来。返回一个RACDynamicSignal.

  • 序号2 . 当signal信号调用bind进行绑定,会调用block5

  • 序号3 . [RACSignal createSignal] 内部会创建RACDynamicSignal用didSubscribeblock6 copy保存起来。返回一个RACDynamicSignal的bindSignal

  • 序号4 .当订阅者开始订阅bindSignal的时候,也就是subscribeNext内部会创建订阅者,然后self.didSubscribe(subscriber),即执行didSubscribe的block,即执行block6

  • 序号5 .在block6 的第一句代码,即RACStreamBindBlock bindingBlock = block(),这里的block是外面传进来的block2,于是开始调用block2。

  • 序号6 .执行完block2,会返回一个RACStreamBindBlock的对象。赋值给bindingBlock,bindingBlock就是block3,注意此时还没有执行block3,

  • 序号7 .由于是源信号signal调用的bind函数,所以bind函数里面的self就是源信号signal,在bind内部订阅了源信号signal。内部会创建订阅者,订阅者里面用nextblock属性保存了block10,然后self.didSubscribe(subscriber)。由于前面self.didSubscribe 存储的就是block1,所以会执行block1。

  • 序号8 .执行block1sendNext调用订阅者subscribernextBlock,于是开始执行block10

  • 序号9 . block10中会先调用bindingBlock,这个是之前调用block2的返回值,这个RACStreamBindBlock对象里面保存的是block3。所以开始调用block3

  • 序号10 . 在block3中入参是一个value,这个valuesignalsendNext中发出来的value的值,在block3中可以对value进行变换,变换完成后,返回一个新的信号signal’(类型为RACReturnSignal)。

  • 序号11 .如果返回的signal'为空,则会调用completeSignal,即调用block7block7中会发送sendCompleted。如果返回的signal'不为空,则会调用addSignal,即调用block8。

  • 序号12 .block8中会继续订阅signal'。由于signal'是外面bind函数的返回值,返回值的信号是RACReturnSignal类型的,所以一订阅就会sendNext,就会执行block9

  • 序号13 . block9 中会sendNext,这里的subscriberblock6的入参,于是对subscriber调用sendNext,会调用到bindSignal的订阅者的block4中。

  • 序号14 .block9 中执行完sendNext,还会调用sendCompleted。这里的是在执行block9里面的completed闭包。

  • 序号15 .completeSignal(signal, selfDisposable);然后又会调用completeSignal,即block7
    执行完block7,bind整个流程就完成了。

一句话总结:bind操作方法实质上就是生成新的绑定信号,利用returnSignal作为中间信号来改变源数据生成新的数据并执行新绑定信号的nextBlock代码块!

相关文章

网友评论

    本文标题:RACSignal操作的核心bind实现分析

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