不可发送类型“[String:Any]?” 在调用非隔离实例方法 XXX 时退出主参与者隔离上下文无法跨越参与者边界

Tom*_*you 8 ios swift

我有一个如下所示的函数:

public final class MyClass {
  static let shared = MyClass()

  public func doSomething(dictionary: [String: Any]? = nil) async -> UIViewController {
    return await UIViewController()
  }
}
Run Code Online (Sandbox Code Playgroud)

我在 a 中这样称呼它UIViewController

final class MyViewController: UIViewController {
  @IBAction private func tapButton() {
    Task {
      let vc = await MyClass.shared.doSomething()
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但这给了我一个警告:

不可发送类型“[String:Any]?” 在调用非隔离实例方法“doSomething(dictionary:)”时退出主参与者隔离上下文无法跨越参与者边界

请注意,您必须Strict Concurrency Checking在“构建设置”中将其设置为CompleteTargeted使其显示在 Xcode 中。

我知道 a 内的函数UIViewController与 MainActor 是隔离的,我希望tapButton()如此。但是我该怎么做才能避免这个警告呢?

Swe*_*per 5

该字典据说“退出主要参与者隔离的上下文”和“跨参与者边界”,因为它MyViewController是一个@MainActor类,但MyClass事实并非如此。运行的doSomething不是主角,而是协作线程池。

Sendable对于像非类型这样的人[String: Any]?来说,跨越演员边界是不安全的。[String: Any]?不是Sendable因为Any不是Sendable。是的,你只是经过nil这里,这应该是安全的,但 Swift 只查看类型。

有几种方法可以解决这个问题。以下是我想到的一些:

  • 取一个[String: any Sendable]?代替
  • 注释MyClassdoSomething@MainActor
  • 使用Task.detached而不是Task.init,以便协作线程池也运行该任务。Task.init将继承当前的 actor 上下文,并且在 处tapButton,它是主要 actor。