我需要使用
GCD
实现的代码的大致示例:
func performTask(completion: (() -> ())?) {
doSomeAsyncTask { [weak self] isSuccess in
if isSuccess {
self?.handleResult(completion: completion)
} else {
completion?()
self?.handleResult(completion: nil)
}
}
}
func handleResult(completion: (() -> ())?) {
...
}
func doSomeAsyncTask(completion: ((Bool) -> ())?) {
//example of async task which can be successful or not
DispatchQueue.main.async {
completion?(Bool.random())
}
}
我想用
async/await
重写它,但我不知道如何实现performTask
。其他方法:
func handleResult() async {
...
}
func doSomeAsyncTask() async -> Bool {
await withCheckedContinuation { checkedContinuation in
Task {
checkedContinuation.resume(returning: Bool.random())
}
}
}
您能解释一下如何实施吗
performTask
?我不明白如何处理有时方法应该调用完成而有时不调用的情况。
非常简单
func performTask() async -> Bool {
return await withCheckedContinuation { continuation in
doSomeAsyncTask { isSuccess in
continuation.resume(returning: isSuccess)
}
}
}
performTask
异步返回完成处理程序的结果
在完成处理程序的再现中,如果
doSomeAsyncTask
返回 false
,它会立即调用闭包,然后使用 handleResult
调用 nil
作为完成处理程序。这是一个非常奇怪的模式。我唯一能猜测的是,其目的是如果 doSomeAsyncTask
失败,立即调用完成处理程序,但无论如何仍然调用 handleResult
,但如果成功,则在 handleResult
完成之前不返回。
如果这是您的意图,Swift 并发演绎可能是:
@discardableResult
func performTask() async -> Bool {
let isSuccess = await doSomeAsyncTask()
if isSuccess {
await handleResult()
} else {
Task { await handleResult() }
}
return isSuccess
}
注意,我返回
doSomeAsyncTask
的成功或失败,因为作为最佳实践,您始终希望调用者能够知道它是否成功(即使您当前不关心)。因此,我将其设为 @discardableResult
,以防调用者当前不关心它是成功还是失败。
另一种模式是如果不成功则抛出错误(如果调用者此时不关心成功或失败,则可以
try?
)。
enum ProcessError: Error {
case failed
}
func performTask() async throws {
if await doSomeAsyncTask() {
await handleResult()
} else {
Task { await handleResult() }
throw ProcessError.failed
}
}
显示了您提供的代码的直译后,我倾向于使用更简单的模式:
@discardableResult
func performTask() async -> Bool {
let isSuccess = await doSomeAsyncTask()
await handleResult()
return isSuccess
}
在上面的前两个替代方案中,我使用非结构化并发来处理
doSomeAsyncTask
返回 false 的场景,并允许函数立即返回结果,然后稍后异步执行 handleResult
。这(就像完成处理程序的再现)引出了如何处理取消的问题。问题是 handleResult
是否足够慢以证明该模式合理,或者这是否是过早优化的情况。人们想要在成功路径中而不是在失败路径中等待handleResult
,这似乎非常奇怪。第三个也是最后一个示例简化了这个逻辑。目前我们对原始完成处理程序演绎的基本原理还不够了解,无法回答这个问题。