英文:
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 { // <- 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
这个调用,因为你正在等待它。
你必须处于一个异步上下文中才能使用await
。viewDidLoad()
不是一个异步方法,所以它不会创建异步上下文。这与类或@MainActor
无关。方法本身必须标记为async
(你不能在这里这样做,因为超类的实现不是异步的)。
所以你需要创建一个异步上下文,通常的做法是使用Task
。
另一种说法是viewDidLoad
的调用者被承诺该方法不会挂起。如果它可能会挂起,那么它将被标记为async
。viewDidLoad
必须在不调用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 {…}
.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论