RACMulticastConnection介紹

在介紹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。所以本質,仍是有多個訂閱者,但是訂閱的副作用只發生一次,所以表現出共享訂閱者的行為。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容