Craig Gidney
Craig Gidney

Reputation: 18316

Is there a ReactiveCocoa method like publish, but that forwards the latest value to new subscribers?

I often use ReactiveCocoa to track the latest value of some variable, like the text in a text field. Sometimes these latest values are actually themselves computed, in a way that multiple subscriptions causes the computations to happen multiple times. Often it would be significantly more efficient to merge these computations.

What I would like to use is RACSignal* sharedComputationLatest = complicatedLatestValue.publish.autoconnect, but then when new subscribers subscribe to the shared computation signal they are not told the latest value.

Is there a variant of publish, some sort of publishLatest, that already exists and does what I need? If not, does it already exist and have a name in .Net's Rx?

Update: It turns out that autoconnect has slightly different semantics than I thought, namely that if the number of subscribers goes to zero and then back up there is no re-connection. I needed the re-connection bit, so I implemented my own method (in an answer below).

Upvotes: 2

Views: 649

Answers (2)

Craig Gidney
Craig Gidney

Reputation: 18316

Here's a custom implementation (note: not thread safe):

-(RACSignal*) publishLatestAutoreconnect {
    __block int32_t subscriberCount = 0;
    __block RACDisposable* subscription = nil;
    __block RACReplaySubject* publishSubject = nil;

    return [RACSignal createSignal:^RACDisposable*(id<RACSubscriber> subscriber) {
        __block RACDisposable* _subscriberDisposable = nil;

        // auto[re]connect if we had no subscribers
        subscriberCount++;
        if (subscriberCount == 1) {
            publishSubject = [RACReplaySubject replaySubjectWithCapacity:1];
            subscription = [self subscribe:publishSubject];
        }

        // forward to subscriber
        _subscriberDisposable = [publishSubject subscribe:subscriber];

        return [RACDisposable disposableWithBlock:^{
            // stop forwarding to subscriber
            [_subscriberDisposable dispose];

            // disconnect if we now have no subscribers
            subscriberCount--;
            if (subscriberCount == 0) {
                [subscription dispose];
                subscription = nil;
                publishSubject = nil;
            }
        }];
    }];
}

Upvotes: 1

Justin Spahr-Summers
Justin Spahr-Summers

Reputation: 16973

Sounds like you want -replayLast.

Upvotes: 4

Related Questions