SceneKit适配Swift 6并发遇阻:SCNSceneRendererDelegate调用问题求解
此前我的问题被错误标记为SpriteKit相关问题的重复,但实际我的问题聚焦于SceneKit:SceneKit线程调用代理方法时无法修改SCNNode导致功能失效,与SpriteKit的Sendable闭包问题完全无关,对方的解决方案无法解决我的问题。
随后我咨询苹果论坛,得到苹果员工的回复:
我建议您针对SceneKit提交bug报告。我认为您的判断是对的:目前应暂时使用Swift 5语言模式。
我正尝试将SceneKit项目移植到Swift 6,但始终找不到可行方案,怀疑SceneKit与Swift 6并发模型暂不兼容,只能暂时保留Swift 5模式。
SCNSceneRendererDelegate的方法在SceneKit线程中调用:
若代理是ViewController,代码如下:
class GameViewController: UIViewController { let aNode = SCNNode() func renderer(_ renderer: any SCNSceneRenderer, updateAtTime time: TimeInterval) { aNode.position.x = 10 } }
编译器会报错:Main actor-isolated instance method 'renderer(_:updateAtTime:)' cannot be used to satisfy nonisolated protocol requirement,这符合Swift 6的并发规则。
编译器给出两种满足协议一致性的方式,但都存在问题:
方式一:使用
@preconcurrency声明协议一致性class GameViewController: UIViewController, @preconcurrency SCNSceneRendererDelegate { }这种方式只是将并发检查延迟到运行时,会导致SceneKit线程运行时崩溃。
方式二:将代理方法声明为
nonisolatednonisolated func renderer(_ renderer: any SCNSceneRenderer, updateAtTime time: TimeInterval) { aNode.position.x = 10 }此时编译器会报错:
Main actor-isolated property 'position' can not be mutated from a nonisolated context,因为SCNNode的属性属于Main Actor隔离,无法在非隔离上下文修改。
即使代理不是ViewController而是nonisolated类,仍然会遇到无法操作SCNNode的问题。几乎所有SCNSceneRendererDelegate的实现都会用到SCNNode这类绑定到Main Actor的类型,这也是该代理的设计初衷。
那么,我哪里出错了?如何在完整Swift 6编译环境下正确使用SceneKit的SCNSceneRendererDelegate方法?目前这是否可行?
内容的提问来源于stack exchange,提问作者AirXygène

