combineLatest has different behaviour in Just vs Future

772 views Asked by At

In Combine there are (among others) these two publishers:

let just = Just("Just")
let future = Future<String, Never>({ (promise) in
    DispatchQueue.main.async {
        promise(.success("Future"))
    }
})

These two have a different output when put into a combineLatest publisher like in the following

just.combineLatest([1,2,3].publisher).sink { (value) in
    print(value)
}.store(in: &bin)
/* prints
("Just", 1)
("Just", 2)
("Just", 3)
*/

future.combineLatest([1,2,3].publisher).sink { (value) in
    print(value)
}.store(in: &bin)
/* prints:
("Future", 3)
*/

Is there any way to modify (e.g. an operator) the Future publisher in a way so that it will behave like the Just publisher?

1

There are 1 answers

2
Dávid Pásztor On

Future doesn't behave differently when you call combineLatest on it. Your example is simply flawed due to the async dispatch you add inside your Future.

combineLatest only emits a value when all of its upstreams emitted a value. So if you add a DispatchQueue.main.async before you called promise inside your Future, you'll delay the emission in your Future. Because of this, Future will emit later than the Array.publisher and hence you'll only see 1 (or sometimes 0, depending on when the next runloop on the main thread is executed) outputs from combineLatest.

As soon as you remove the async call, you see the same output from Future and Just.

var subscriptions = Set<AnyCancellable>()

let just = Just("Just")
let future = Future<String, Never> { promise in
    promise(.success("Future"))
}

just.combineLatest([1,2,3].publisher).sink { (value) in
    print(value)
}.store(in: &subscriptions)

future.combineLatest([1,2,3].publisher).sink { (value) in
    print(value)
}.store(in: &subscriptions)