Swift。如何在不使用Task的情况下在viewDidLoad()中使用并发。

huangapple go评论75阅读模式
英文:

Swift. How to use concurrency with viewDidLoad() without Task

问题

在我的理解中,UIViewController@MainActor,所以如果我想从 override func viewDidLoad 启动并发代码,我不需要编写 Task {}。但现在需要。是否有一种在 UIViewController 中使用并发而不编写 Task { 的方法?

示例:

let interactor: InteractorInterface

override func viewDidLoad() {
    super.viewDidLoad()

    setupUI()

    // 已经是主角

    Task { // <- 为什么需要它?
        let request = TestModels.DidLoad.Request()
        await interactor?.viewDidLoad(request: request)
    }
}

protocol InteractorInterface {
    func viewDidLoad(request: TestModels.DidLoad.Request) async
}

actor Interactor: InteractorInterface { ... }
英文:

It can be strange question, but in my understanding UIViewController is @MainActor, so if I want to start concurrency code from override func viewDidLoad, I don't need to write Task {}. But now it needed. Is there any way to use concurrency from UIViewController without writing Task {?

Example:

let interactor: InteractorInterace

override func viewDidLoad() {
    super.viewDidLoad()

    setupUI()

    // Already main actor

    Task { // &lt;- why we need it?
        let request = TestModels.DidLoad.Request()
        await interactor?.viewDidLoad(request: request)
    }
}

protocol InteractorInterface {
    func viewDidLoad(request: TestModels.DidLoad.Request) async
}

actor Interactor: InteractorInterface { ... }

答案1

得分: 1

你没有展示interactor是什么,但我会假设它要么是一个不是@MainActor的actor,要么viewDidLoad(request:)本身是一个异步方法。在任何一种情况下,你都需要await这个调用,因为你正在等待它。

你必须处于一个异步上下文中才能使用awaitviewDidLoad()不是一个异步方法,所以它不会创建异步上下文。这与类或@MainActor无关。方法本身必须标记为async(你不能在这里这样做,因为超类的实现不是异步的)。

所以你需要创建一个异步上下文,通常的做法是使用Task

另一种说法是viewDidLoad的调用者被承诺该方法不会挂起。如果它可能会挂起,那么它将被标记为asyncviewDidLoad必须在不调用await的情况下返回。因此,你必须将那个await移到一个单独的Task中,并立即返回。

英文:

You haven't shown what interactor is, but I'll assume it is either an actor that is not @MainActor, or viewDidLoad(request:) is itself an async method. In either case, you would have to await the call, as you are.

You must be in an asynchronous context in order to await. viewDidLoad() is not an async method, so it does not create an async context. It has nothing to do with the class or @MainActor. The method itself must be marked async (you can't do that here, since the superclass implementation is not async).

So you need to create an async context, and the common way to do that is with Task.

Another way to say this is that the caller of viewDidLoad is promised that the method will not suspend. If it could suspend, then it would be marked async. viewDidLoad must return without calling await. So you must move that await into a separate Task, and return immediately.

答案2

得分: 1

是的,视图控制器需要使用Task {…}来调用另一个方法中的async方法,这个方法可以是(a) async或者(b) 隔离到不同的actor中。

那么,interactor的viewDidLoad(request:)方法实际上是一个async方法吗?如果是的话,那么是的,需要使用Task {…}。在这种情况下,视图控制器隔离到主actor是无关紧要的。这只是进入async上下文的问题。

但如果它只是一个在不同actor中隔离的同步方法呢?如果是这样,您可以考虑将interactor隔离到主actor中,这样视图控制器就不再需要使用Task {…}了。

英文:

Yes, the view controller would need to use Task {…} to invoke an async method from another method that is either (a) async or (b) isolated to a different actor.

So, is the interactor’s viewDidLoad(request:) actually an async method? In so, then, yes, Task {…} is needed. In this scenario, the fact that the view controller is isolated to the main actor is irrelevant. It’s just a matter of getting to an async context.

But is it just a synchronous method isolated to a different actor? If so, you could consider isolating the interactor to the main actor, instead, in which case the view controller would no longer need to use Task {…}.

huangapple
  • 本文由 发表于 2023年7月7日 03:24:35
  • 转载请务必保留本文链接:https://go.coder-hub.com/76631975.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定