使用 GCD 将代码转换为 Swift 中的 async/await?

问题描述 投票:0回答:2

我需要使用

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
?我不明白如何处理有时方法应该调用完成而有时不调用的情况。

swift grand-central-dispatch completion swift-concurrency
2个回答
0
投票

非常简单

func performTask() async -> Bool {
    return await withCheckedContinuation { continuation in
        doSomeAsyncTask { isSuccess in
            continuation.resume(returning: isSuccess)
        }
    }
}

performTask
异步返回完成处理程序的结果


0
投票

在完成处理程序的再现中,如果

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
,这似乎非常奇怪。第三个也是最后一个示例简化了这个逻辑。目前我们对原始完成处理程序演绎的基本原理还不够了解,无法回答这个问题。

© www.soinside.com 2019 - 2024. All rights reserved.