SKCameraNode实例化异常:直接赋值失败,先存变量再赋值成功的原因?
为什么直接赋值
self.camera = SKCameraNode()会返回nil? 这事儿我之前踩过一模一样的坑!根本不是什么奇怪的Bug,是Swift的ARC(自动引用计数)和SpriteKitcamera属性的特性在共同搞事情~
核心原因:SKScene的camera是弱引用
SpriteKit里SKScene的camera属性被定义为weak var camera: SKCameraNode?。弱引用的特点是:它不会增加对象的引用计数,一旦没有任何强引用指向这个对象,ARC就会立即把它释放掉。
两种写法的差异瞬间就清晰了:
- 直接赋值的情况:当你执行
self.camera = SKCameraNode()时,新创建的SKCameraNode实例没有任何强引用持有它——self.camera是弱引用,留不住它。所以这条语句刚执行完,ARC就把这个节点释放了,self.camera自然就变成nil。 - 先创建局部变量的情况:
let c = SKCameraNode()会生成一个强引用的局部变量,牢牢攥住这个节点实例。当你把c赋值给self.camera后,只要c还在当前作用域内(比如方法没执行完),节点就不会被释放。如果之后你调用self.addChild(c),场景的节点树会再给这个节点加一个强引用,就算局部变量c的作用域结束,节点也能存活,self.camera就能一直指向它。
简单验证一下
你可以在两种写法后立刻打印状态(调试用):
// 直接赋值的情况 self.camera = SKCameraNode() print(self.camera) // 输出 nil // 局部变量的情况 let c = SKCameraNode() self.camera = c print(self.camera) // 输出 Optional(<SKCameraNode>...) self.addChild(c) // 就算局部变量作用域结束,camera也不会变成nil
正确写法建议
不管用哪种方式,一定要把相机节点添加到场景的节点树中,这样场景会强引用它,彻底避免被释放的问题:
let cameraNode = SKCameraNode() self.camera = cameraNode self.addChild(cameraNode) // 要是非得直接赋值,记得立刻addChild self.camera = SKCameraNode() if let camera = self.camera { self.addChild(camera) }
内容的提问来源于stack exchange,提问作者Jean-Baptiste Yunès
相关产品推荐
相关产品推荐

