ios - 全部完成后 ReactiveSwift 管道计数失败
问题描述
我在ReactiveSwift中有一个用于上传的管道。我想确保即使其中一个上传失败,其余的也不会被中断。
在所有这些都成功或失败后,我应该从performUploads
方法中返回成功,或者如果有任何失败,我应该返回错误,所以下一步,下载部分不会开始。即使有错误,所有上传都应该有机会上传,它们不应该被停止。
有没有办法确定上传完成后是否有任何错误?请参阅此处的方法:
let pendingUploadItemsArray: [Items] = ...
func performUploads() -> SignalProducer<(), MyError> {
return upload(pendingUploadItemsArray)
.then(doAnything())
}
private func upload(_ items: [Items]) -> SignalProducer<Signal<(), MyError>.Event, Never> {
let producers = items
.filter { item in
return item.readyForUpload
}
.map { self.upload($0).materialize() }
return SignalProducer.merge(producers)
}
private func upload(_ item: Item) -> SignalProducer<(), MyError> {
return internalUploader.upload(item)
.on(failed: failedToUpload(item),
value: successfullyUploaded(item))
.ignoreValues()
}
internalUploader
上传方法是:
func upload(_ item: Item) -> SignalProducer<Any, MyError>
然后在另一个类中,您将调用此上传器:
let sync = self.uploader.performUploads()
.then(startDownloads())
只有在startDownloads
所有上传都成功完成时才应该运行。感谢您的任何见解。
这可能是应该以完全不同的方式完成的事情。
解决方案
我不知道您的代码到底在做什么successfullyUploaded
和failedToUpload
在做什么,但大概您正在跟踪成功和失败以提供某种实时进度 UI。这就是我将如何构建它:
struct UploadResult {
let item: Item
let error: Error? // nil if the upload succeeded
var succeeded: Bool { error == nil }
var failed: Bool { !succeeded }
}
...
static func upload(_ items: [Item]) -> SignalProducer<[UploadResult], Never> {
SignalProducer(items)
.filter(\.readyForUpload)
.flatMap(.merge) { item in
Self.internalUploader(item)
.map { UploadResult(item: item, error: nil) }
.flatMapError { error in
SignalProducer(value: UploadResult(item: item, error: error))
}
}
.scan(into: [UploadResult]()) { ( results: inout [UploadResult], nextResult) in
results.append(nextResult)
}
}
- 我创建了一个
UploadResult
结构,它表示上传成功或失败的项目。 - 在
upload
函数中,我不是创建一个生产者数组然后合并它们,而是将项目数组转换为项目的信号生产者,SignalProducer(items)
然后使用flatMap(.merge)
将上传的内容合并为单个信号生产者。 materialize
我没有使用 ,而是将map
成功上传的文件转换为.UploadResult
flatMapError
UploadResult
- 我用来
scan
在每次上传完成时累积结果。每次上传完成(成功或出错)时,scan
将发送更新的上传结果数组,可用于更新 UI。
然后你可以像这样使用它:
Uploader.upload(someItems)
.on(value: { resultsSoFar in
// Update UI here
})
.take(last: 1)
.attempt { results in
if !results.allSatisfy(\.succeeded) {
// At least one of the uploads failed, so send an error
throw MyError()
}
}
.then(startDownloads)
- 我使用
on(value:)
运算符根据当前结果更新 UI。每次下载成功或失败时,都会使用更新的结果调用此闭包。 - 我
take(last: 1)
用来过滤掉所有中间结果;它只会在所有上传完成后发送最终结果。 - 我
attempt
用来检查是否有任何上传失败,如果失败则抛出错误。这确保只有在所有上传成功后才会开始下载。
希望这可以处理您的用例,但是如果我错过了有关更广泛背景的某些内容,请在评论中告诉我!
编辑
如果您只关心一次处理一个结果而不是作为一个正在运行的数组,您可以摆脱scan
然后替换take(last: 1)
为collect
:
static func upload(_ items: [Item]) -> SignalProducer<UploadResult, Never> {
SignalProducer(items)
.filter(\.readyForUpload)
.flatMap(.merge) { item in
Self.internalUploader(item)
.map { UploadResult(item: item, error: nil) }
.flatMapError { error in
SignalProducer(value: UploadResult(item: item, error: error))
}
}
}
...
Uploader.upload(someItems)
.on(value: { latestResult in
// Do something with the latest result
})
.collect()
.attempt { results in
if !results.allSatisfy(\.succeeded) {
// At least one of the uploads failed, so send an error
throw MyError()
}
}
.then(startDownloads)
推荐阅读
- django - 在 django 的“for”循环中使用“if”调用函数不起作用
- pine-script - tradingview pine 中的不规则交易执行顺序
- javascript - html 元素正在选择超出其范围的点击事件
- spring - 单个端点的 Spring boot/CRNK 自定义查询规范 URL 映射
- javascript - 如何使用 React 突出显示选项卡
- c# - 使用 rigibody.MovePosition 时,刚体不会与物体发生碰撞
- javascript - 使用命名集合展平嵌套的 json 数组
- mongodb - Spring Data MongoDB @DBRef 为子类加载 null
- javascript - 如何在 ASP.NET MVC 应用程序中测试客户端 JavaScript?
- javascript - Chrome 和 IE11 中用户定义的 window.close 函数行为之间的差异