如何正确摆脱这个并发编译错误?

问题描述 投票:0回答:3
@MainActor
class A {}

class VC: UIViewController {
  let foo: A

  init() {
    self.foo = A() // Error: Call to main actor-isolated initializer 'init()' in a synchronous nonisolated context
    super.init(nibName: nil, bundle: nil)
  }

  @MainActor
  init() {
    self.foo = A() // Compiles
    super.init(nibName: nil, bundle: nil)
  }

  init(_ void: Void = ()) { 
    self.foo = A() // Compiles
    super.init(nibName: nil, bundle: nil)
  }
}

我知道

A()
应该在主要参与者初始化器上调用,但为什么第一个初始化器不从 @MainActor
继承
UIViewController
?为什么
Void
参数消除了错误(即使使用
-warn-concurrency
)?

注意:如果我用

VC
注释
@MainActor
,我会在第一个初始化器中得到与
super.init
相同的错误,而第三个初始化器仍然有效。

ios swift concurrency swift-concurrency
3个回答
1
投票

@MainActor
限制所有方法和属性可从 A 类的主线程进行访问。

let foo: A
不是类 A,它是存储对类 A 的引用的实例,您没有采取任何措施来使设置 foo 线程安全。
init
的其中一个
VC
设置为仅在设置 foo 的主线程中执行,但另一个可以由任何线程调用并设置 foo。

编辑:我认为您可能会发现有用的更多信息 如果您的唯一目标是线程安全,那么使用 MainActor 不是一个好方法,这意味着只有与 GUI 交互相关的线程才能访问您的类,这可能会阻止某些必须在主线程中运行的实际代码执行,因为线程安全你可能更好地使用参与者,它们像类一样工作,但一次只能有一个线程在其中,它们可以是任何线程,并且不同的方法可以由不同的线程在不同的时间访问,但只有一个会一次只是演员。


1
投票

您还可以通过添加初始化器并标记它来解决问题

nonisolated

@MainActor
class A {
    nonisolated init() {}
    func load() async -> String {
        return "Async!"
    }
}

0
投票

我的问题是我没有在视图中包含@MainActor,但在底层 Store/State 上注释了宏

© www.soinside.com 2019 - 2024. All rights reserved.