美文网首页
RAC中Multicast的实现原理分析

RAC中Multicast的实现原理分析

作者: 海洋顶端 | 来源:发表于2016-08-27 16:01 被阅读0次

    1. 为什么要用Multicast?

    RACMulticastConnection类的注释如下:

    /// A multicast connection encapsulates the idea of sharing one subscription to a
    /// signal to many subscribers. This is most often needed if the subscription to
    /// the underlying signal involves side-effects or shouldn't be called more than
    /// once.
    

    从注释中可以知道,Multicast的作用是让side effect代码只被执行一次。我们知道,普通Signal每次被subscribe,都会执行side effect代码。如果side effect代码性能开销很大并且重复执行结果相同,那么确保side effect代码只被执行一次就很有意义,Multicast就是做的这个事情。


    2. Multicast是如何确保side effect代码只被执行一次?

    为了解答这个问题,我们要知道为什么普通Signal每次被subscribe,都会执行side effect代码。
    一般,我们会调用下面这个方法创建Signal,所有的side effect代码的都包含在didSubscribe这个Block中。

    + (RACSignal *)createSignal:(RACDisposable * (^)(id<RACSubscriber> subscriber))didSubscribe;
    

    Signal在被subscribe的时候会执行这个Block,源码如下(省略非关键代码):

    - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
                、、、
                RACDisposable *innerDisposable = self.didSubscribe(subscriber);
                、、、
    }
    

    我们调用doNext、flatten、concat等Operation对Signal进行变换,内部多是创建一个新的Signal,这个新的Signal的didSubcribe中会subscirbe要变换的Signal。所以使用Operation对Signal进行变换得到的Signal,被subscribe的时候会一层一层向上去subscribe最原始的Signal,一层一层向上去执行didSubscribe Block,最终所有的side effect代码都会被执行。

    那么Multicast是如何做到side effect仅被执行一次的?
    注释是这么说的A multicast connection encapsulates the idea of sharing one subscription to a signal to many subscribers.。看源码可以知道,内部是利用RACSubject在中间转发消息,RACSubject(_signal)订阅真正的Signal(sourceSignal),外部Subscribers订阅RACSubject(_signal),如下图所示:

    未命名.png
    源码如下(省略非关键代码):
    - (RACDisposable *)connect {
        BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);
    
        if (shouldConnect) {
            self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];
        }
    
        return self.serialDisposable;
    }
    
    - (RACSignal *)autoconnect {
        、、、
        return [[RACSignal
            createSignal:^(id<RACSubscriber> subscriber) {
                、、、
                RACDisposable *subscriptionDisposable = [self.signal subscribe:subscriber];
                RACDisposable *connectionDisposable = [self connect];
                、、、
            }]
            setNameWithFormat:@"[%@] -autoconnect", self.signal.name];
    }
    

    从上面源码还可以看出,autoconnect是lazy的,有外部订阅者订阅的时候,才调用connect方法,让subject订阅sourceSignal。
    这里的关键是RACSubject,它既是sourceSignal的订阅者,也是外部subscribers的数据源。RACSubject会被订阅多次,而sourceSignal只会被订阅一次,它的didSubscribe Block只会被执行一次,只会产生一次副作用。

    相关文章

      网友评论

          本文标题:RAC中Multicast的实现原理分析

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