对于@MainActor 属性仅使用 `await` 而不是 `await MainActor.run { }`

Use only `await` instead `await MainActor.run { }` for @MainActor properties

假设一个 ObservableObject 如下:

class NavigationModel: ObservableObject {
  @MainActor @Published name: String = ""
}

在主队列中的异步代码块 运行 not 中更改已发布的 属性 时,我通常使用以下语法:

await MainActor.run {
  name = "foobar"
}

不过,我发现下面的语法也可以无错编译:

await name = "foobar"

我想知道这条短路径是否有效并提供相同的结果?

是的,这两个代码段的行为相同。 await 将导致当前异步调用“跳转”主要参与者并在那里执行。

编译器(以及 Swift 运行 时间)知道 name 只能从主 thread/actor 访问,因此将要求您:

  1. 从具有 @MainActor 上下文的异步块访问 属性。
  2. 从当前线程跳到主角那里执行。然后,之后恢复执行当前函数(但是,该函数可以在与跳转到主要参与者之前最初执行的线程不同的线程上恢复)。

您的第一个代码片段基本上执行了这两个步骤,将 @MainActor 范围引入到 运行 您的代码中,然后您跳转到主要参与者执行它,然后再继续您的功能称呼。 第二个片段只是跳过范围创建部分,运行在主要角色上使用单行代码,然后立即跳回来。

如果你运行在主要演员身上做多件事你会想减少执行的跳跃次数,因为如果你跳跃的话这会引入很多开销[=34= 】 往返于主要演员。 例如:

@MainActor func someUIOperation() async { ... }

func expensiveLotsOfHopsToMainActor() async {
    for _ in 0..<100 {
        await someUIOperation()
    }
}

func betterOnlyOneHopToMainActor() async {
    await MainActor.run {
        for _ in 0..<100 {
           someUIOperation()
        }
    }
}

请参阅 original pitch for @MainActor 中的示例和更多内容。