子类化SCNNode引发Swift 6并发问题的原因咨询
关于SCNNode子类化的Swift并发隔离问题
问题背景
我尝试子类化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+完整并发检查,此时出现以下并发错误:
Main actor-isolated initializer 'init()' has different actor isolation from nonisolated overridden declaration; this is an error in the Swift 6 language mode
改用以下写法后问题解决:
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:)标记为@MainActor,会出现类似警告:
Main actor-isolated initializer 'init(coder:)' has different actor isolation from nonisolated overridden declaration; this is an error in the Swift 6 language mode
我的问题:
- 为什么
init(size:)与init?(coder:)表现不同? - 为什么标记
MyContainer3D为nonisolated并标记init(size:)为@MainActor可解决警告?
问题解答
1. init(size:)与init?(coder:)的表现差异
init(size:)是自定义初始化方法,父类SCNNode中没有对应的声明。这类自定义方法的actor隔离属性不受父类约束,你可以根据需求自由指定,只要内部调用符合并发规则即可。init?(coder:)是遵循NSCoding协议的必须实现方法,父类SCNNode中的该方法为nonisolated。在Swift并发模型中,重写或实现继承/协议要求的方法时,必须保持与原声明一致的actor隔离级别。如果给它标记@MainActor,就会和父类的nonisolated声明冲突,触发警告。
2. 标记类为nonisolated并给自定义初始化器加@MainActor的原因
- 当默认隔离域设置为主Actor后,你的
MyContainer3D类会被隐式标记为@MainActor,所有成员默认继承该隔离级别。此时调用父类的init()(它是nonisolated的)就会出现隔离级别冲突——子类初始化器默认的@MainActor隔离和父类无隔离的init()不兼容,Swift 6会将这种冲突视为错误。 - 把类标记为
nonisolated后,类本身不再默认绑定主Actor,所有成员默认都是nonisolated。这时给自定义的init(size:)标记@MainActor,既满足了你在主Actor上初始化节点、修改属性的需求,又不会和父类的nonisolated初始化器冲突。而init?(coder:)因为要严格遵循父类的nonisolated声明,保持无标记即可符合并发规则。
内容的提问来源于stack exchange,提问作者HL666
相关产品推荐
相关产品推荐

