在不支持并发的函数中等待 Swift 5.5 中的两个任务完成的正确方法是什么?

What is the correct way to await the completion of two Tasks in Swift 5.5 in a function that does not support concurrency?

我有一个应用程序可以对给定的字符串进行一些处理,这在 2 Task 秒内完成。在这段时间里,我正在展示一个动画。当这些 Task 完成后,我需要隐藏动画。下面的代码有效,但看起来不太好。我相信有更好的方法来做到这一点?

let firTask = Task {
    /* Slow-running code */
}

let airportTask = Task {
    /* Even more slow-running code */
}

Task {
    _ = await firTask.result
    _ = await airportTask.result
    
    self.isVerifyingRoute = false
}

我会通过扩展使任务可丢弃。也许是这样的:

extension Task {
    @discardableResult
    func finish() async -> Result<Success, Failure>  {
        await self.result
    }
}

那么您可以将加载任务更改为:

Task {
    defer { self.isVerifyingRoute = false }
    await firTask.finish()
    await airportTask.finish()
}

真正的问题不就是误用了Task吗?正如您所发现的,任务本身并不是您可以等待的东西。如果目标是 运行 降低后台代码的速度,请使用 actor。然后你可以用 await 干净地调用一个 actor 方法。

let myActor = MyActor()
await myActor.doFirStuff()
await myActor.doAirportStuff()
self.isVerifyingRoute = false

但是,当我们与 self 对话时,我们还需要确保我们在主线程上——您的代码忽略了这一点。这是一个例子:

actor MyActor {
    func doFirStuff() async {
        print("starting", #function)
        await Task.sleep(2 * 1_000_000_000)
        print("finished", #function)
    }
    func doAirportStuff() async {
        print("starting", #function)
        await Task.sleep(2 * 1_000_000_000)
        print("finished", #function)
    }
}
func test() {
    let myActor = MyActor()
    Task {
        await myActor.doFirStuff()
        await myActor.doAirportStuff()
        Task { @MainActor in
            self.isVerifyingRoute = false
        }
    }
}

一切都在正确的模式下发生:耗时的事情发生在后台线程上,对 self 的调用发生在主线程上。在我看来,处理主线程调用的一种看起来更简洁的方法是使用 @MainActor 方法:

func test() {
    let myActor = MyActor()
    Task {
        await myActor.doFirStuff()
        await myActor.doAirportStuff()
        self.finish()
    }
}
@MainActor func finish() {
    self.isVerifyingRoute = false
}

我认为它优雅而清晰。