美文网首页
RACMulticastConnection介绍

RACMulticastConnection介绍

作者: 解放者莫雷尔 | 来源:发表于2016-09-12 18:57 被阅读0次

    在介绍RACMulticastConnection之前,先说明一个Reactive Cocoa中其他几个用到的类。

    RACReplaySubject

    RACSubject

    RACSubject继承RACSignal,同时也实现了RACSubscriber协议,可以看成是一个可以手动控制发送next、completed和error的信号。

    RACReplaySubject继承了RACSubject,它会保存已发送的值的(固定上限数量),每次有新的订阅者,它都会将这些值重新发送给这些新的订阅者,对于error和completed也是同样的。RACReplaySubject重新实现了subscriber协议,使得这个类有了一些不同的行为。

    它有一个valuesReceived属性来存储接收到的值,每次有新的订阅者时,便将valuesReceived数组中的所有值发送给订阅者。

    RACMulticastConnection

    Multicast意为“多播”,multicast connection的意图是将一次对信号的订阅分享给多个订阅者。常见的使用情形就是:涉及的信号包含了side effect或者不希望它被多次调用。

    RACMulticastConnection对外暴露的接口和属性只有三个:

    • signal 表示这个多播信号
    • - (RACDisposable *)connect,通过订阅signal来与它进行连接。只有调用了connect方法,信号才被订阅,在此之前signal不回接收任何值
    • - (RACSignal *)autoconnect,当返回的signal被订阅时,立刻connect多播信号,当返回的信号没有订阅者时,自动清除多播信号的订阅。

    注意,不要主动创建RACMulticastConnection。使用RACSignal的publish或multicast方法来创建。

    RACMulticastConnection的初始化方法是私有的,其实现方式如下:

    - (id)initWithSourceSignal:(RACSignal *)source subject:(RACSubject *)subject {
        NSCParameterAssert(source != nil);
        NSCParameterAssert(subject != nil);
    
        self = [super init];
        if (self == nil) return nil;
    
        _sourceSignal = source;//原信号
        _serialDisposable = [[RACSerialDisposable alloc] init];
        _signal = subject;//对外暴露的多播信号
        
        return self;
    }
    

    关于connect的源代码其实也很简单:

    - (RACDisposable *)connect {
        BOOL shouldConnect = OSAtomicCompareAndSwap32Barrier(0, 1, &_hasConnected);
    
        if (shouldConnect) {
            self.serialDisposable.disposable = [self.sourceSignal subscribe:_signal];//关键
        }
    
        return self.serialDisposable;
    }
    

    其实它主要做的就是让对外暴露的多播信号订阅原信号。RACMulticastConnection只是提供了实现多播的原型功能,我们真正使用到的还是RACSignal定义的相关的多播操作。

    - (RACMulticastConnection *)publish {
        RACSubject *subject = [[RACSubject subject] setNameWithFormat:@"[%@] -publish", self.name];
        RACMulticastConnection *connection = [self multicast:subject];
        return connection;
    }
    
    - (RACMulticastConnection *)multicast:(RACSubject *)subject {
        [subject setNameWithFormat:@"[%@] -multicast: %@", self.name, subject.name];
        RACMulticastConnection *connection = [[RACMulticastConnection alloc] initWithSourceSignal:self subject:subject];
        return connection;
    }
    

    publish和multicast都会创建返回一个多播连接,将原来信号转换成一个RACSubject信号.本质上,RACMulticastConnection只是为普通RACSignal与RACSubject、RACReplaySubject架起一座桥梁。

    那么,多播的特性:多个订阅者共享一个订阅行为是如何实现的呢?在RACDynamicSignal的subscriber协议中,对subscribe的实现有这么一段:

        if (self.didSubscribe != NULL) {
            RACDisposable *schedulingDisposable = [RACScheduler.subscriptionScheduler schedule:^{
                RACDisposable *innerDisposable = self.didSubscribe(subscriber);
                [disposable addDisposable:innerDisposable];
            }];
    
            [disposable addDisposable:schedulingDisposable];
        }
    

    可以看出,每次订阅发生时,都会执行一次订阅的block。而RACSubject的subscribe协议方法的实现如下:

    - (RACDisposable *)subscribe:(id<RACSubscriber>)subscriber {
        NSCParameterAssert(subscriber != nil);
    
        RACCompoundDisposable *disposable = [RACCompoundDisposable compoundDisposable];
        subscriber = [[RACPassthroughSubscriber alloc] initWithSubscriber:subscriber signal:self disposable:disposable];
    
        NSMutableArray *subscribers = self.subscribers;
        @synchronized (subscribers) {
            [subscribers addObject:subscriber];
        }
        
        return [RACDisposable disposableWithBlock:^{
            @synchronized (subscribers) {
                // Since newer subscribers are generally shorter-lived, search
                // starting from the end of the list.
                NSUInteger index = [subscribers indexOfObjectWithOptions:NSEnumerationReverse passingTest:^ BOOL (id<RACSubscriber> obj, NSUInteger index, BOOL *stop) {
                    return obj == subscriber;
                }];
    
                if (index != NSNotFound) [subscribers removeObjectAtIndex:index];
            }
        }];
    }
    

    它只是将subscriber添加到了队列当中,并没有再执行订阅的block。所以本质,仍是有多个订阅者,但是订阅的副作用只发生一次,所以表现出共享订阅者的行为。

    相关文章

      网友评论

          本文标题:RACMulticastConnection介绍

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