swift - 从异步完成处理程序中中断“for”循环
问题描述
我的应用程序(Swift 5)使用循环内的异步完成处理程序将文件发送到服务器,并使用for
信号量来确保同时只发送一个文件。
如果上传失败或出现异常,我想打破循环以显示错误消息。
我的代码:
let group = DispatchGroup()
let queue = DispatchQueue(label: "someLabel")
let sema = DispatchSemaphore(value: 0)
queue.async {
for (i,item) in myArray.enumerated() {
group.enter()
do {
let data = try Data(contentsOf: item.url)
ftpProvider.uploadData(folder: "", filename: item.filename, data: data, multipleFiles: true, completion: { (success, error) in
if success {
print("Upload successful!")
} else {
print("Upload failed!")
//TODO: Break here!
}
group.leave()
sema.signal()
})
sema.wait()
} catch {
print("Error: \(error.localizedDescription)")
//TODO: Break here!
}
}
}
group.notify(queue: queue) {
DispatchQueue.main.async {
print("Done!")
}
}
添加 abreak
会给我一条错误消息:
未标记的“break”仅允许在循环或开关内使用,需要标记的 break 才能退出 if 或 do
向循环 ( myLoop: for (i,s) in myArray.enumerated()
) 添加标签也不起作用:
使用未解决的标签“myLoop”
break self.myLoop
也失败了。
在第一个文件的上传完成之前添加一个print
权利group.enter()
证明循环不仅仅是在第一个文件的上传完成之前完成,而是在“上传成功”/“上传失败”之前打印文本(正如它应该的那样)。由于这种破坏应该是可能的:
如何打破循环,以便从内部显示错误对话框group.notify
?
解决方案
我建议的方法是基于此问题AsynchronousOperation
的已接受答案中提供的。
创建类,复制代码并创建一个AsynchronousOperation
包含异步任务和完成处理程序的子类
class FTPOperation: AsynchronousOperation {
var completion : ((Result<Bool,Error>) -> Void)?
let item : Item // replace Item with your custom class
init(item : Item) {
self.item = item
}
override func main() {
do {
let data = try Data(contentsOf: item.url)
ftpProvider.uploadData(folder: "", filename: item.filename, data: data, multipleFiles: true) { (success, error) in
if success {
completion?(.success(true))
} else {
completion?(.failure(error))
}
self.finish()
}
} catch {
completion?(.failure(error))
self.finish()
}
}
}
在控制器中添加一个串行操作队列
let operationQueue : OperationQueue = {
let queue = OperationQueue()
queue.name = "FTPQueue"
queue.maxConcurrentOperationCount = 1
return queue
}()
并运行操作。如果返回错误,则取消所有挂起的操作
for item in myArray {
let operation = FTPOperation(item: item)
operation.completion = { result in
switch result {
case .success(_) : print("OK", item.filename)
case .failure(let error) :
print(error)
self.operationQueue.cancelAllOperations()
}
}
operationQueue.addOperation(operation)
}
在方法中加print
一行来证明finish()
AsynchronousOperation
推荐阅读
- python - 在python中加载一个json文件后“转置”一个数组?
- android - 使用 Android 模拟器进行 Visual Studio Code Apache Cordova 调试
- sql - 如何返回id包含某些数字的特定序列PostgreSQL查询的所有记录
- python - python绑定到windows上的接口和端口
- python - Pandas:在 MultiIndex 数据框中的每个索引之后添加一个空行
- swift - 切换选项卡时删除所有子视图控制器并快速移动到父视图控制器
- android - 任务':android_intent:compileDebugJavaWithJavac'的Flutter执行失败
- c# - .net Core 模型的依赖注入
- node.js - JOSE 错误 [ERR_PACKAGE_PATH_NOT_EXPORTED]
- ruby-on-rails - ror 我如何订购有很多价值