0

我有一个应用程序可以在给定字符串的情况下进行一些处理,这是在 2Task秒内完成的。在此期间,我正在显示动画。当这些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
}
4

2 回答 2

5

这不是滥用Task的真正问题吗?正如您所发现的,任务本身并不是您可以等待的事情。如果目标是在后台运行慢代码,请使用演员。然后你可以用 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
}

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

于 2021-08-10T12:42:37.397 回答
2

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

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

然后您可以将加载任务更改为:

Task {
    defer { self.isVerifyingRoute = false }
    await firTask.finish()
    await airportTask.finish()
}
于 2021-08-10T12:19:32.337 回答