[英]Swift Combine: Run a list of publishers one after the other, and publish the first non-nil element
I have a list of combine publishers that each publish one optional value.我有一个联合发布者列表,每个发布者发布一个可选值。 From this list, i want to create a publisher, that runs the upstream publishers in the sequence they appear in the list, one after the other , and then publish the first non-nil item i can find.
从这个列表中,我想创建一个发布者,它按照它们在列表中出现的顺序运行上游发布者,一个接一个,然后发布我能找到的第一个非零项目。
My first approach was我的第一种方法是
publishers
.publisher
.flatMap(identity)
.first(where: {$0 != nil})
but this causes all publishers to run, and the fastest to win.但这会导致所有发布者都运行,并且以最快的速度获胜。
I created a minimal example with a solution that comes close to what i want to achieve.我创建了一个最小的示例,其解决方案接近我想要实现的目标。
import Combine
import Foundation
import PlaygroundSupport
PlaygroundPage.current.needsIndefiniteExecution = true
func delayedPublisher<Value>(_ value: Value?, delay after: Double) -> AnyPublisher<Value?, Never> {
let p = PassthroughSubject<Value?, Never>()
DispatchQueue.main.asyncAfter(deadline: .now() + after) {
p.send(value)
p.send(completion: .finished)
}
return p.eraseToAnyPublisher()
}
let delays = [1,2,3,4,5].map({ Bool.random() ? nil : $0 }).shuffled()
print("Creating publishers with values and delays (in seconds)", delays)
let myPublishers = delays
.map{ delayedPublisher($0, delay: Double($0 ?? 1))
.print("\(String(describing: $0))")
.eraseToAnyPublisher() }
let cancel = myPublishers
.publisher
.flatMap { $0 }
.collect()
.map { resultList in
resultList.first(where: { $0 != nil }) ?? nil
}
.sink { result in
print("result:", result ?? "nil")
}
This creates a bunch of publishers with different delays, that may or may not produce a value.这会创建一堆具有不同延迟的发布者,这些发布者可能会也可能不会产生价值。 I then collect all results, and pick the first non-nil value.
然后我收集所有结果,并选择第一个非零值。 The problem is
问题是
I did my research but found nothing like that, perhaps because combine is not really designed to do that sort of thing.我做了我的研究,但没有发现类似的东西,也许是因为 combine 并不是真正设计用来做那种事情的。 So any pointers are appreciated.
因此,任何指针都值得赞赏。
The approach is almost like your original one, but you need to restrict flatMap
to run at most one publisher at a time with maxPublishers
parameter:该方法几乎就像您原来的方法一样,但是您需要使用
maxPublishers
参数限制flatMap
一次最多运行一个发布者:
publishers
.publisher
.flatMap(maxPublishers: .max(1), { $0 })
.compactMap { $0 } // Remove all nil values and unwrap the non-nil ones.
.first()
Here's a simple extension to Publisher这是 Publisher 的一个简单扩展
extension Publisher {
func chain(with publisher: @escaping () -> AnyPublisher<Output, Failure>) -> AnyPublisher<Output, Failure> {
self.flatMap { _ in publisher() }.eraseToAnyPublisher()
}
}
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.