如何使构成Combine框架的异步管道同步(串行)排列?
假设我有50个URL,我想从中下载相应的资源,假设我想一次完成一个。我知道如何使用Operation / OperationQueue做到这一点,例如,使用在下载完成之前不会声明自身完成的Operation子类。我如何使用Combine做同一件事?
目前我所要做的就是保留剩余URL的全局列表并弹出一个列表,为一个下载设置一个管道,进行下载,然后在sink该管道中重复执行。看起来不太像Combine。
sink
我确实尝试制作了一系列URL,并将其映射到一系列发布者。我知道我可以“产生”一个发布者,并使其使用进行发布flatMap。但是,我仍然同时进行所有下载。没有任何可组合方式以受控方式遍历数组- 或存在吗?
flatMap
(我也曾想过要对Future进行一些操作,但我变得无望地感到困惑。我不习惯这种思维方式。)
我仅对此进行了简短的测试,但是乍一看似乎每个请求在开始之前都等待上一个请求完成。
我正在发布此解决方案以寻求反馈。如果这不是一个好的解决方案,请务必提出批评。
extension Collection where Element: Publisher { func serialize() -> AnyPublisher<Element.Output, Element.Failure>? { // If the collection is empty, we can't just create an arbititary publisher // so we return nil to indicate that we had nothing to serialize. if isEmpty { return nil } // We know at this point that it's safe to grab the first publisher. let first = self.first! // If there was only a single publisher then we can just return it. if count == 1 { return first.eraseToAnyPublisher() } // We're going to build up the output starting with the first publisher. var output = first.eraseToAnyPublisher() // We iterate over the rest of the publishers (skipping over the first.) for publisher in self.dropFirst() { // We build up the output by appending the next publisher. output = output.append(publisher).eraseToAnyPublisher() } return output } }
此解决方案的更简洁版本(由@matt提供):
extension Collection where Element: Publisher { func serialize() -> AnyPublisher<Element.Output, Element.Failure>? { guard let start = self.first else { return nil } return self.dropFirst().reduce(start.eraseToAnyPublisher()) { $0.append($1).eraseToAnyPublisher() } } }