如何在不引起数据竞争的情况下删除 SKNode?

问题描述 投票:0回答:1

我正在使用 SpriteKit 编写一个 iOS 应用程序,但我发现有关从其父级中删除

SKNode
的信息存在冲突,这使我陷入了僵局。

数据竞争在 SpriteKit 文档中专门解决了:

如果您在 SpriteKit 框架深处遇到分段错误或其他类型的崩溃,则您的代码很可能正在场景委托回调之外修改 SpriteKit 对象。

所以我知道我应该只在这些回调中修改(删除)节点。事实上,当使用删除主队列上的节点的完成块运行

SKAction
时,我可靠地经历了数据竞争/崩溃/异常。甚至
SKAction.removeFromParent
操作本身也会引发异常并变得基本上无法使用。

SKNode.removeFromParent()

 更新回调中调用 
SKScene
 会引发异常并记录一条控制台消息,表明仅允许在主线程中删除节点。这与文档相矛盾,所以我闻到了 Apple 一些被遗忘的代码。

这与

SpriteKit 文档的另一部分冲突

SKViewDelegate、SKSceneDelegate 和 SKScene 的所有 SpriteKit 回调都发生在主线程中,因此,这些是访问或操作节点的安全位置。

但是,我可以通过在重写的

SKScene

 方法中放置一个断点来证明 
SKScene.update(:) 回调不在主线程中被调用
。它们在某些 SceneKit 渲染串行队列中被调用。

在我的应用程序中,我使用

SCNSceneRenderer.overlaySKScene

SKScene
 来补充 
SCNScene
。在 SceneKit 中,事情可能会有所不同,但它仍然是一个 SpriteKit 场景。

那么现在是什么情况?我

无法删除更新回调中的节点,因为它没有在主队列上调用。我也无法删除主队列中的节点,因为它会导致数据竞争。

解决方案#1是根本不删除任何节点,但这并不是真正的解决方案。有些节点,例如SKShapeNode

,有一个固定的框架,只能在初始化时设置。我可以将它们移动到隐藏的“墓地”节点或缓存节点,但这只是一些开箱即用的解决方法。

解决方案#2是通过暂停SCNView

来防止数据竞争,然后等到最后一帧完成渲染,然后才删除主线程中的节点,然后再次取消暂停视图。这很麻烦,而且一开始就没有必要。它要求我找到一些静止帧(黑色交叉淡入淡出过渡?),我可以在其中暂停视图而不打扰用户。

有人遇到过这样的麻烦并找到其他方法吗?

我有一种感觉,Apple 在 iOS 8 中实现了

SCNSceneRenderer.overlaySKScene

,然后在未来几年进行了其他更改,然后就忘记了它。

ios race-condition sknode
1个回答
0
投票
所以我知道我应该只在这些回调中修改(删除)节点。事实上,当使用删除主队列上的节点的完成块运行 SKAction 时,我可靠地经历了数据竞争/崩溃/异常。甚至 SKAction.removeFromParent 操作本身也会引发异常并变得基本上无法使用。

© www.soinside.com 2019 - 2024. All rights reserved.