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



我有一个应用程序,做一些处理给定的字符串,这是在2Tasks完成。在此期间,我正在显示一个动画。当这些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
}

真正的问题不就是这是对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
}

我认为这是优雅而清晰的。

我会使用扩展使任务可丢弃。也许像这样:

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

然后你可以把你的加载任务改为:

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