Search code examples
swiftreactive-programmingcombine

Swift Combine - Multiple Observable (CurrentValueSubject or PassthroughSubject) into one but wait for update from all


Ok, so I am using the last version of Swift with Combine. My goal is to combine 3 CurrentValueSubject or PassthroughSubject into one Sequence by waiting for all of them to emit once.

Let's take the following example:

var var1 = CurrentValueSubject<[String], Never>)([])
var var2 = CurrentValueSubject<Int, Never>(0)
var var3 = CurrentValueSubject<Date?, Never>(nil)

I want to have all value in one when they each emit a new sequence.

So I could do something like that:

Publishers
    .CombineLatest3(var1, var2, var3)
    .sink(receivedValue: { var1, var2, var3 in
        print("Printed!")
    })
    .store(in: &subscriptions)

Alright, so that kind of works, but it will print Printed! 3 times on the second pass. Let's say, if I do the following code, it will do it only once.

var1.send(["test","test1"])
var2.send(0)
var3.send(Date())

but I add this

var1.send(["test","test1"])
var2.send(0)
var3.send(Date())
var1.send(["test","test1"])

It will trigger again my Combined Publishers. And I want to trigger it again only if I have the following scenario:

var1.send(["test","test1"])
var2.send(0)
var3.send(Date())
var1.send(["test2","test3"])
var2.send(2)
var3.send(Date())

I hope this makes sense, let me know if you have an idea of how to tackle this issue!


Solution

  • Zip3 seems to be what you are looking for:

    Publishers
        .Zip3(var1, var2, var3)
        .sink(receivedValue: { var1, var2, var3 in
            print("Printed!")
        })
        .store(in: &subscriptions)
    

    From the docs of zip:

    Use zip(_:_:) to return a new publisher that combines the elements from two additional publishers to publish a tuple to the downstream. The returned publisher waits until all three publishers have emitted an event, then delivers the oldest unconsumed event from each publisher as a tuple to the subscriber.

    See a visualisation on RxMarbles!