Reputation: 21883
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
Reputation: 270790
You can do a reduce
on the array, with each partial result being computed by append
ing 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