在调用声明为@MainActor 的异步函数的任务中使用@MainActor
Using @MainActor in a Task which is calling async function declared as @MainActor
考虑到以下代码块,我想了解是否需要将任务本身声明为 MainActor。
func login() {
Task { [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
final class LoginService {
@MainActor
func start() async -> LoginResult {
// Doing some UI related operations here
}
}
当在 Task 内部调用的异步函数已经声明为 MainActor 时,是否还需要将 Task 本身声明为 MainActor?像这样:
func login() {
Task { @MainActor [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
我相信如果一个 Task 本身被声明为 MainActor,如果没有另外声明,子异步操作将继承父配置,但它是否也可以反过来工作?
你说:
I believe if a Task
itself is declared as MainActor
, child async operations will inherit the parent’s configuration if not declared otherwise, …
是的,但我会谨慎地假设这一点,因为 child 的 actor 上下文经常像您所说的那样“以其他方式声明”。编写依赖于这些假设的代码是轻率的:我们希望我们的类型尽可能松散耦合。
… but does it also work the other way around?
不,parent一般不会继承child的actor context。
例外情况是,如果 parent 没有声明特定的 actor 上下文,它的延续(await
之后的代码)可能 运行 在 child 的演员正在使用(不过,IIRC,对此没有正式的保证,我建议不要依赖任何此类假设)。
但是 Swift 并发的美妙之处在于我们不应该关心 child 使用什么(例如,登录服务使用什么 actor 上下文),因为任何代码(例如“欢迎消息”的呈现)要求特定参与者应该简单地声明自己。 “显示欢迎消息”功能的职责是指示它需要主要参与者,而不是调用者。
如果每个 child 在各自适当的 actor 上下文中成功 运行,那么 login
方法现在根本不需要担心这个。
Do I need to declare the Task
itself as MainActor
too when the async
function which is called inside the Task
is declared as MainActor
already? Like this:
func login() {
Task { @MainActor [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
你可以做到。
就个人而言,如上所述,我会简单地用 @MainActor
注释 showWelcomeMessage
(或整个 class,如果有意义的话),而不是这个闭包。必须在主要角色上显示消息,而不是结果检查代码。 login
现在不需要对登录服务或“显示消息”例程进行任何假设。
考虑到以下代码块,我想了解是否需要将任务本身声明为 MainActor。
func login() {
Task { [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
final class LoginService {
@MainActor
func start() async -> LoginResult {
// Doing some UI related operations here
}
}
当在 Task 内部调用的异步函数已经声明为 MainActor 时,是否还需要将 Task 本身声明为 MainActor?像这样:
func login() {
Task { @MainActor [weak self] in
let result = await self?.loginService.start()
if result == .successful {
self?.showWelcomeMessage() // updating the UI here
}
}
}
我相信如果一个 Task 本身被声明为 MainActor,如果没有另外声明,子异步操作将继承父配置,但它是否也可以反过来工作?
你说:
I believe if a
Task
itself is declared asMainActor
, child async operations will inherit the parent’s configuration if not declared otherwise, …
是的,但我会谨慎地假设这一点,因为 child 的 actor 上下文经常像您所说的那样“以其他方式声明”。编写依赖于这些假设的代码是轻率的:我们希望我们的类型尽可能松散耦合。
… but does it also work the other way around?
不,parent一般不会继承child的actor context。
例外情况是,如果 parent 没有声明特定的 actor 上下文,它的延续(await
之后的代码)可能 运行 在 child 的演员正在使用(不过,IIRC,对此没有正式的保证,我建议不要依赖任何此类假设)。
但是 Swift 并发的美妙之处在于我们不应该关心 child 使用什么(例如,登录服务使用什么 actor 上下文),因为任何代码(例如“欢迎消息”的呈现)要求特定参与者应该简单地声明自己。 “显示欢迎消息”功能的职责是指示它需要主要参与者,而不是调用者。
如果每个 child 在各自适当的 actor 上下文中成功 运行,那么 login
方法现在根本不需要担心这个。
Do I need to declare the
Task
itself asMainActor
too when theasync
function which is called inside theTask
is declared asMainActor
already? Like this:func login() { Task { @MainActor [weak self] in let result = await self?.loginService.start() if result == .successful { self?.showWelcomeMessage() // updating the UI here } } }
你可以做到。
就个人而言,如上所述,我会简单地用 @MainActor
注释 showWelcomeMessage
(或整个 class,如果有意义的话),而不是这个闭包。必须在主要角色上显示消息,而不是结果检查代码。 login
现在不需要对登录服务或“显示消息”例程进行任何假设。