Combine - collect()

collect() is a powerful operator that enables us to receive all at once the outputs from a publisher.

It collects all received elements, and emits a single array of the collection when the upstream publisher finishes.

[0, 1, 2, 3].publisher
    .sink { (output) in
        print(output)
    }.store(in: &subscriptions)

The publisher will emit the values as they come — e.g starting with 0 and ending with 3 —

// 0
// 1
// 2
// 3

Using collect(), the publisher will hold up the values and emit all of them once a finished event is sent — e.g when the last element of the sequence is emitted —

[0, 1, 2, 3].publisher
    .collect()
    .sink { (output) in
        print(output)
    }.store(in: &subscriptions

// [0, 1, 2, 3]

The nice thing about collect() is that we can combine it with the MergeMany built-in publisher to handle efficiently multiple asynchronous requests.

MergeMany will create a single publisher from multiple sources and once it finishes, the outputs will be sent to the downstream subscriber all at once.

Let’s create some delay to simulate asynchronous network requests.

let publishers = [0, 1, 2, 3]
    .map { n in
        Just(n).delay(for: .seconds(Int.random(in: 24)),
                                   scheduler: DispatchQueue.main)
    }
        
Publishers.MergeMany(publishers)
    .collect()
    .sink { (output) in
        print(output)
    }.store(in: &subscriptions)

The MergeMany publisher won’t emit any values until all upstream publishers complete their tasks— e.g Just will deliver a single output and then finishes—

// [1, 0, 2, 3]