从场景根节点中移除SCNNode节点导致在SceneKit中崩溃。

22
我想要从场景中移除一组节点,这些节点代表了一条路径。它们是SCNSphere几何节点和自定义几何节点的组合,使用SCNGeometrySource和SCNGeometryElement创建表示线条。
我没有将这些节点保留在任何类型的数组中。相反,我通过它们的名称搜索场景中根节点的第一个级别的节点树,并随后调用一个动作序列,使它们逐渐消失,并应该从根节点中删除。
代码如下:
func clearPath() {
    //
    let disappear = SCNAction.fadeOut(duration: 0.1)
    let remove = SCNAction.removeFromParentNode()
    let sequence = SCNAction.sequence([disappear, remove])

    if let pathNodesToRemove = pathNodes() {
        //
        for node in pathNodesToRemove {
            //
            node.removeAllActions()
            node.runAction(sequence)
        }
    }

    if let lineNodesToRemove = lineNodes() {
        for node in lineNodesToRemove {
            //
            node.removeAllActions()
            node.runAction(sequence)
        }
    }

    path.removeAll()
}

其中:

func pathNodes() -> [SCNNode]? {
    //

...        

    let nodes = rootNode.childNodes.filter { (node) -> Bool in
        //
        guard let name = node.name else { return false }
        if name.hasPrefix(configurationComponent.id) &&
            name.range(of:"_PATH") != nil {
            return true
        } else {
            return false
        }
    }

    return nodes
}

lineNodes()函数基本上是一样的。

我打开了僵尸对象来跟踪错误的来源,我总是得到相同的错误:在线程上调用SceneKit`C3DNodeRemoveFromParentNode作为最后一件事情,并且出现了EXC_BAD_ACCESS(code=1,address...)。

clearPath()函数是整个应用程序中我唯一调用'RemoveFromParentNode'的地方。

这些节点上没有物理体,并且也没有在其他地方被保留。

有什么想法如何解决这个问题吗?

编辑28/4/18:

这里是发生错误的线程的崩溃报告。看起来removeObjectFromChildNodesAtIndex被调用了两次...

    Thread 9 name:  Dispatch queue: com.apple.scenekit.renderingQueue.Air_Relay.ARTCSCNView0x104126720
Thread 9 Crashed:
0   SceneKit                        0x00000001957d668c C3DNodeRemoveFromParentNode + 40
1   SceneKit                        0x0000000195826e28 -[SCNNode __removeObjectFromChildNodesAtIndex:] + 184
2   SceneKit                        0x0000000195826e28 -[SCNNode __removeObjectFromChildNodesAtIndex:] + 184
3   SceneKit                        0x0000000195827350 -[SCNNode removeFromParentNode] + 396
4   SceneKit                        0x000000019593e9fc -[SCNActionRemove updateWithTarget:forTime:] + 92
5   SceneKit                        0x0000000195907cb8 SCNCActionSequence::cpp_updateWithTargetForTime+ 2202808 (SCNNode*, double) + 316
6   SceneKit                        0x00000001957bcfb0 SCNActionApply + 112
7   SceneKit                        0x0000000195853d2c _applyActions + 236
8   CoreFoundation                  0x00000001814dccbc __CFDictionaryApplyFunction_block_invoke + 24
9   CoreFoundation                  0x00000001814c3f98 CFBasicHashApply + 132
10  CoreFoundation                  0x00000001814cdb64 CFDictionaryApplyFunction + 288
11  SceneKit                        0x0000000195853b5c C3DAnimationManagerApplyActions + 92
12  SceneKit                        0x000000019583b054 -[SCNRenderer _update:] + 656
13  SceneKit                        0x000000019583d018 -[SCNRenderer _drawSceneWithNewRenderer:] + 252
14  SceneKit                        0x000000019583d69c -[SCNRenderer _drawScene:] + 84
15  SceneKit                        0x000000019583daa0 -[SCNRenderer _drawAtTime:] + 728
16  SceneKit                        0x00000001958e446c -[SCNView _drawAtTime:] + 512

编辑 30/04/18

我继续给应用程序添加其他功能,需要使用SCNAction.removeFromParentNode()来删除节点。我将它们隔离出来,使其独立于上述代码而引起问题。

在每个新节点生成时,它们会更频繁地调用SCNRendererDelegate更新。

我还尝试直接在节点上使用removeFromParentNode(),使用SCNAction.run块,同样的问题也会发生。


如果存在保留循环,即使未存储在数组中,使用removeNodes仍然可能导致崩溃。请尝试在泄漏检测中检查您的引用计数。 - Voltan
pathNodes()和lineNodes()是否可能返回一个共同的节点?path.removeAll()是什么意思?(clearPath方法中的最后一行) - Peter Parker
1个回答

1
当您使用SCNAction.removeFromParentNode()时,您并没有删除节点,您需要自己删除该节点。如果您删除路径或动作,则基本上会使值为空,因此当调用路径或动作时,现在存在一个空值并且会导致崩溃。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接