在调用非隔离实例方法XXX时,非可发送类型'[String : Any]?'退出主演员隔离上下文,无法跨越演员边界。

6

我有一个函数长这样:

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

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

我在 UIViewController 中这样调用它:

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

但是它给了我一个警告:

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

请注意,您必须将构建设置中的Strict Concurrency Checking设置为CompleteTargeted,才能在Xcode中显示此设置。

我知道UIViewController内部的函数被隔离到MainActor,而我想让tapButton()也是如此。但是我该怎么做才能避免这个警告呢?


@Sweeper,我刚刚更新了,使用给我的代码可以重现问题。 - Tometoyou
@Sweeper 啊,我没意识到只有启用了才会显示。问题已更新。 - Tometoyou
你可以将字典参数中的值类型 Any 替换为 Sendable - Joakim Danielson
2个回答

3

字典被称为“退出主要演员隔离上下文”和“跨演员边界”,因为MyViewController是一个@MainActor类,但MyClass不是。无论运行doSomething的是什么,都不是主要演员,而是协作线程池。

[String: Any]?这样的非Sendable类型越过演员边界是不安全的。[String: Any]?不是Sendable,因为Any不是Sendable。是的,你只传递了nil,这应该是安全的,但Swift只看类型。

有几种解决方法。以下是我想到的一些:

  • 改为使用 [String: any Sendable]?
  • MyClassdoSomething 上加上注释 @MainActor
  • 使用 Task.detached 代替 Task.init,这样协作线程池也会运行任务。 Task.init 将继承当前的 actor 上下文,在 tapButton 中,它是主 actor。

问题:any Sendable 兼容哪个版本的 Swift?5.5+? - Tometoyou
@Tometoyou 我不确定,但是 SendableSE提案说“已实现(Swift 5.7)”,因此我认为它在 Swift 5.5 或 5.6 中不可用。 - Sweeper

0

在“目标”并发警告下,你不能跨并发边界传递[String: Any],因为它不是(也不能是)Sendable。即使它是一个默认参数,它仍然在调用上下文中创建,然后传递给接收上下文。为了避免这种情况,你需要在接收上下文中创建默认参数。默认参数只是显式重载的快捷方式,所以你可以明确地编写重载:

// Remove the default parameter here
public func doSomething(dictionary: [String: Any]?) async -> UIViewController {
    return await UIViewController()
}

// And define it explicitly as an overload
public func doSomething() async -> UIViewController {
    return await doSomething(dictionary: nil)
}

有了这个,对doSomething()的调用就不会创建一个Sendable问题。

话虽如此,我认为MyClass实际上应该是@MainActor(或者至少是doSomething)。如果我没记错的话,在非主队列上创建UIViewController是合法的(尽管可能不是),但在主队列之外调用它的任何方法都是不合法的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接