drekka
drekka

Reputation: 21883

Swift Combine: How do I merge the results from several nested Publishers?

I'm working on some code and trying to use Combine to streamline the process. So far I have a list of objects, each of which has a property that returns a Publisher. The objects conform to a protocol and I'm trying to do something like this:

protocol StringPublisher {
    var stringValues: AnyPublisher<String, Error> { get }
}

let objArray:[StringPublisher] = [StringPublisher1("a","b","c"), StringPublisher2("x","y","z")]

let results: [String] = objArray.?

So what I'm trying to do with this is to read the objArray instances in sequence, get each one's stringValues publisher and process the values it produces until it finishes, then listen for values from the next one until it finishes and so on. So the above would give:

a
b
c
x
y
z

I think I need to do something like this:

let results:[String] = objArray.flatMap(maxPublishers: .max(1)) { $0.stringValues }.sink { value in
    print(value)
}

But I'm still trying to get this all to compile and work.

Has anyone tried something like this and how did you combine the results from publishers in multiple objects?

Upvotes: 1

Views: 1637

Answers (1)

Sweeper
Sweeper

Reputation: 270790

You can do a reduce on the array, with each partial result being computed by appending the publishers in the array. Then, use collect to get a Publisher<[String], Error>.

let stringArrayPublisher = objArray.reduce(Empty().eraseToAnyPublisher()) {
    result, pub in result.append(pub.stringValues).eraseToAnyPublisher()
}.collect()
stringArrayPublisher.sink { completion in
    print(completion)
} receiveValue: { value in
    print("published \(value)")
}

For example, if you had

class ExampleStringPublisher: StringPublisher {
    var stringValues: AnyPublisher<String, Error>
    
    init(_ strings: String...) {
        stringValues = strings.publisher.setFailureType(to: Error.self).eraseToAnyPublisher()
    }
}
let objArray:[StringPublisher] = [ExampleStringPublisher("a","b","c"), ExampleStringPublisher("x","y","z")]

The output would be:

published ["a", "b", "c", "x", "y", "z"]
finished

Upvotes: 1

Related Questions