RACSignal操作的核心bind实现分析

先来说说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代码块!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,509评论 6 504
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,806评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 163,875评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,441评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,488评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,365评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,190评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,062评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,500评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,706评论 3 335
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,834评论 1 347
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,559评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,167评论 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,779评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,912评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,958评论 2 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,779评论 2 354

推荐阅读更多精彩内容