对SCNNode进行子类化会引发Swift 6的并发问题

移动开发 2026-07-09

我想对SCNNode进行子类化:

open class MyContainer3D: SCNNode {

  public init(size: SCNVector3) {
    super.init()
    self.boundingBox = (min: SCNVector3(0, 0, 0), max: SCNVector3(size.x, size.y, size.z))
    self.position = SCNVector3(0, 0, 0)
  }

  @available(*, unavailable)
  public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  } 
}

我已将默认隔离域设为主actor,并使用Swift 5+完整并发性检查。

这会带来并发性问题:

主actor隔离的初始化器 'init()' 与非隔离的覆盖声明具有不同的actor隔离性;在Swift 6语言模式下这是一个错误。

不过,如果我这样做,就能工作了:

nonisolated open class MyContainer3D: SCNNode {

  @MainActor
  public init(size: SCNVector3) {
    super.init()
    self.boundingBox = (min: SCNVector3(0, 0, 0), max: SCNVector3(size.x, size.y, size.z))
    self.position = SCNVector3(0, 0, 0)
  }

  @available(*, unavailable)
  public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }

}

我的观察:如果把 init?(coder:)(第二个初始化器)标记为主actor,那么将会得到类似的警告:“主actor隔离的初始化器 'init(coder:)' 与非隔离的覆盖声明具有不同的actor隔离性;在Swift 6语言模式下这是一个错误。”

我的问题:

  1. 为什么 init(size:)init?(coder:) 的行为不同?
  2. 为什么把 MyContainer3D 标记为非隔离并把 init(size:) 标记为非隔离就能消除这个警告?

解决方案

我找到一个不错的变通方法,可以让SCNNode具备主隔离。我将直接从 MySCNNode 进行子类化,其实现如下:

// MainActor by default from project settings
open class MySCNNode: SCNNode {

  // calling super.init() from subclass will call this init which is main isolated, 
  // since we marked the original nonisolated init() unavailable 
  public init(_: () = ()) {
    // this main isolated init can still call super's non-isolated init
    super.init()
  }

  // Unlike SpriteKit, SCNNode directly inherit from NSObject, which is non-isolated.
  // The default generated init is still in main actor, however, overridden init cannot change the isolation of superclass.
  // So we manually declare it to be nonisolated. Otherwise will get "Main actor-isolated initializer 'init()' has different actor isolation from nonisolated overridden declaration"
  @available(*, unavailable)
  nonisolated public override init() {
    super.init()
  }

  @available(*, unavailable)
  nonisolated public required init?(coder: NSCoder) {
    fatalError("init(coder:) has not been implemented")
  }
}
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章