RAC bind

系列文章
RACSignal,RACSubject,RACReplaySubject
RAC bind
RAC Merge flatten
RACMulticastConnection
RAC switchToLatest

RAC 的核心操作思想,HOOK,而核心方法bind 就是hook使用的体现。

  1. 在oc中使用hook,可以在方法调用中,替换原方法的实现。rac中也是一样,可以利用hook的思想,在信号和订阅者之间,加入一层新的逻辑。
  2. 正常来说我们发送信号只有信号的订阅者才会接收到消息,而bind会将信号拦截过滤后发送到新的信号订阅者中。
bind的使用:
    RACSubject *subject = [RACSubject subject];
    RACSignal *signal = [subject bind:^RACSignalBindBlock _Nonnull{
        NSLog(@"有订阅者订阅");        // 第二步  订阅信后会触发这里
// MAKR_1 此block 用来过滤信号 在原信号订阅者中会调用
        return ^(id value, BOOL *stop) {   
            NSLog(@"收到原信号数据");     // 第四步  收到信号后,处理完,返回一个新的信号
            NSLog(@"过滤处理以后将新的信号返回出去")
            return [RACReturnSignal return:value];
        };
    }];
    [signal subscribeNext:^(id  _Nullable x) {    //第一步 订阅信号
        NSLog(@"收到最终的信号");
    }];
    [subject sendNext:@"发送信号"];    // 第三部  发送信号

...
// bind 内部实现
    return [[RACSignal createSignal:^(id<RACSubscriber> subscriber) {
// 当bind返回的信号被注册时会调用这里  获取到 bind传入的block用来对原数据进行包装生成新的信号
        RACSignalBindBlock bindingBlock = block();

        __block volatile int32_t signalCount = 1;   // indicates self

        RACCompoundDisposable *compoundDisposable = [RACCompoundDisposable compoundDisposable];

        void (^completeSignal)(RACDisposable *) = ^(RACDisposable *finishedDisposable) {
            if (OSAtomicDecrement32Barrier(&signalCount) == 0) {
                [subscriber sendCompleted];
                [compoundDisposable dispose];
            } else {
                [compoundDisposable removeDisposable:finishedDisposable];
            }
        };

        void (^addSignal)(RACSignal *) = ^(RACSignal *signal) {
            OSAtomicIncrement32Barrier(&signalCount);

            RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
            [compoundDisposable addDisposable:selfDisposable];

            RACDisposable *disposable = [signal subscribeNext:^(id x) {
// MARK_3  这里的  subscriber 还是bind返回信号的  订阅者  所以这里会出来外面对bind信号的订阅者消息
                [subscriber sendNext:x];
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(selfDisposable);
                }
            }];

            selfDisposable.disposable = disposable;
        };

        @autoreleasepool {
            RACSerialDisposable *selfDisposable = [[RACSerialDisposable alloc] init];
            [compoundDisposable addDisposable:selfDisposable];
// 对原信号的订阅  当原信号调用时  会触发这里
            RACDisposable *bindingDisposable = [self subscribeNext:^(id x) {
                // Manually check disposal to handle synchronous errors.
                if (compoundDisposable.disposed) return;

                BOOL stop = NO;
// MARK_2  包装后的信号
                id signal = bindingBlock(x, &stop);

                @autoreleasepool {
                    if (signal != nil) addSignal(signal);  
                    if (signal == nil || stop) {
                        [selfDisposable dispose];
                        completeSignal(selfDisposable);
                    }
                }
            } error:^(NSError *error) {
                [compoundDisposable dispose];
                [subscriber sendError:error];
            } completed:^{
                @autoreleasepool {
                    completeSignal(selfDisposable);
                }
            }];

            selfDisposable.disposable = bindingDisposable;
        }

        return compoundDisposable;
    }] setNameWithFormat:@"[%@] -bind:", self.name];

bind的操作流程

  1. 调用bind方法,会生成一个新的信号。
  2. 对新的信号进行订阅,会触发bind传入的block,这时bind的内部实现会去订阅原信号
  3. 原信号发送后,会触发,bind内部对原信号的订阅者block。这时会调用bind是内部block返回的用来过滤信号的block(对应MAKR_1的block)。
  4. 这是将原数据发送到 MAKR_1 处的block中,获取到一个包装后的信号。(MARK_2 信号 RACReturnSignal 类型)
  5. 然后将 MARK_2 信号进行订阅。而 RACReturnSignal 类型的信号重写了
- (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
    NSCParameterAssert(subscriber != nil);

    return [RACScheduler.subscriptionScheduler schedule:^{
        [subscriber sendNext:self.value];
        [subscriber sendCompleted];
    }];
}

所以当信号订阅时,会立马触发nextBlock

  1. MARK_2 订阅者中调用 bind 信号订阅者去发送信号,所以外部对bind信号订阅的nextBlock这时就会调用(MARK_3)
  2. 这是就完成了整个流程,bind后,原信号发送的消息,会经过bind时传入的block进行过滤,然后返回一个新的消息,发送的bind信号的。
    原信号->bind(生成新信号)
    原信号发送消息->bind Block 进行过滤,然后发送消息到内部一个信号中-> 转发到bind时生成的新信息号中

RAC中运用了很多hook的思想,所以会非常的绕,其实本质有点类似消息转发,将原信号进行包装过滤,在发送到一个新的信号中。

    return [[self bind:^{
        return ^(id value, BOOL *stop) {
            id stream = block(value) ?: [class empty];
            NSCAssert([stream isKindOfClass:RACStream.class], @"Value returned from -flattenMap: is not a stream: %@", stream);

            return stream;
        };
    }] setNameWithFormat:@"[%@] -flattenMap:", self.name];

还有一个很重要的flattenMap方法,其实就是bind的封装。内部就是bind方法的调用,然后可以传入一个block 作为过滤的规则

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

推荐阅读更多精彩内容