swift - 如何解决 SceneKit Renderer "EXC_BAD_ACCESS (code=1, address=0xf000000010a10c10)"?

标签 swift scenekit

这是我遇到的错误,请查看所附图片以获取更多信息。

com.apple.scenekit.scnview-renderer (17): EXC_BAD_ACCESS (code=1, address=0xf000000010a10c10)

错误日志如下: More Info about the error

我可以在调用以下函数时重现此错误,但前提是此函数在一秒钟内被调用多次。如果用户快速点击按钮骑到下一辆车,就会发生这种情况。

如您所见,我尝试将其包装在 DispatchQueue 中以解决我的问题。

您还会注意到,我创建了一个 Bool alreadyCyclingCars 来跟踪 cycleCarNext() 函数是否已完成,然后才能再次调用它。

此函数实质上是遍历 unlockedCars 数组中的所有 unlockedCars

如果汽车类型与我们当前正在寻找的汽车类型相匹配,我将打破循环。

然后我们判断当前车的索引,看看我需要显示的下一辆车是否是数组中的下一辆(如果有的话)如果不是,我们已经到了数组的末尾所以我显示数组中的第一辆车。

有没有人比我更了解这个? 非常感谢,谢谢!

func cycleCarNext() {
        DispatchQueue.main.async { [weak self] in
            guard let self = self else { return }
            if !self.alreadyCyclingCars {
                self.alreadyCyclingCars = true
                var indexOfCurrentCar = 0
                for (index, car) in UserData.shared.unlockedCars.enumerated() {
                    if car.type == self.overlayScene.currentCarOnDisplay {
                        indexOfCurrentCar = index
                        break
                    }
                }

                if indexOfCurrentCar < UserData.shared.unlockedCars.count - 1 {
                    let nextCar = UserData.shared.unlockedCars[indexOfCurrentCar+1]
                    self.playerNode.removeFromParentNode()
                    self.playerNode = nextCar
                    self.playerNode.name = "player"
                    self.playerNode.position = SCNVector3(x: 17, y: 0.3, z: 0)
                    self.playerNode.eulerAngles = SCNVector3(x: 0, y: toRadians(angle: 45),z: 0)
                    self.scene.rootNode.addChildNode(self.playerNode)
                    self.overlayScene.currentCarOnDisplay = nextCar.type
                    self.overlayScene.updateGarageInterface()
                } else {
                    guard let nextCar = UserData.shared.unlockedCars.first else { return }
                    self.playerNode.removeFromParentNode()
                    self.playerNode = nextCar
                    self.playerNode.name = "player"
                    self.playerNode.position = SCNVector3(x: 17, y: 0.3, z: 0)
                    self.playerNode.eulerAngles = SCNVector3(x: 0, y: toRadians(angle: 45),z: 0)
                    self.scene.rootNode.addChildNode(self.playerNode)
                    self.overlayScene.currentCarOnDisplay = nextCar.type
                    self.overlayScene.updateGarageInterface()
                }
                self.alreadyCyclingCars = false
            }
        }
    }

最佳答案

根据我的经验,当您尝试在 SCNSceneRendererDelegate 之外修改 SceneKit 的场景图(添加/删除节点等)时,会发生此类错误。委托(delegate)方法。

假设您有一个线程以 60fps 的速度执行渲染,而另一个线程(例如主线程)从要渲染的内容中删除一个节点。在某些时候,当渲染线程正在渲染的内容被另一个线程移除时,渲染线程将在渲染过程中进行一部分。这是 EXC_BAD_ACCESS 发生的时间。场景修改的次数越多,您就越有可能看到这种冲突,这就是为什么按钮混搭更容易重现该问题。

解决方法是仅在 SCNSceneRendererDelegate 委托(delegate)方法之一中修改您的场景。我会尝试类似...

func cycleCarNext() {
    self.cycleNextCar = true
}

func renderer(renderer: SCNSceneRenderer, updateAtTime time: NSTimeInterval) {
    if (self.cycleNextCar) {
        self.doCycleNextCar()
        self.cycleNextCar = false
    }
}

func doCycleNextCar() {
    var indexOfCurrentCar = 0
    for (index, car) in UserData.shared.unlockedCars.enumerated() {
        if car.type == self.overlayScene.currentCarOnDisplay {
            indexOfCurrentCar = index
            break
        }
    }

    if indexOfCurrentCar < UserData.shared.unlockedCars.count - 1 {
        let nextCar = UserData.shared.unlockedCars[indexOfCurrentCar+1]
        self.playerNode.removeFromParentNode()
        self.playerNode = nextCar
        self.playerNode.name = "player"
        self.playerNode.position = SCNVector3(x: 17, y: 0.3, z: 0)
        self.playerNode.eulerAngles = SCNVector3(x: 0, y: toRadians(angle: 45),z: 0)
        self.scene.rootNode.addChildNode(self.playerNode)
        self.overlayScene.currentCarOnDisplay = nextCar.type
        self.overlayScene.updateGarageInterface()
    } else {
        guard let nextCar = UserData.shared.unlockedCars.first else { return }
        self.playerNode.removeFromParentNode()
        self.playerNode = nextCar
        self.playerNode.name = "player"
        self.playerNode.position = SCNVector3(x: 17, y: 0.3, z: 0)
        self.playerNode.eulerAngles = SCNVector3(x: 0, y: toRadians(angle: 45),z: 0)
        self.scene.rootNode.addChildNode(self.playerNode)
        self.overlayScene.currentCarOnDisplay = nextCar.type
        self.overlayScene.updateGarageInterface()
    }
}

cycleCarNext 将按当前状态由您的主线程调用。您可能还需要在某处设置 SCNView 的委托(delegate)(例如;sceneView.delegate = self)

想法是,虽然在主线程中立即设置了 cycleCarNext bool 值,但场景并没有改变。相反,更改发生在 SceneKit 渲染循环中的正确时间/线程。

关于swift - 如何解决 SceneKit Renderer "EXC_BAD_ACCESS (code=1, address=0xf000000010a10c10)"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53126186/

相关文章:

ios - 快速获取单例实例

ios - 如何获得我想要的动画?

ios - 从 ViewController 访问 SceneKit-Node

swift - 节点跟随cameraNode及其物理主体

ios - 为什么这段代码不显示任何表格 View ?

ios - 快速避免索引超出范围错误

ios - 如何从 Maya 导出简单的装配模型以用于 Scenekit?

ios - SCNCamera 旋转时应用程序在“后退”按钮上崩溃

swift - 为什么当使用 CGFloat 而不是数字文字时节点的位置会发生变化?

swift - ARKit限制节点的显示距离