【问题标题】:EXC_BAD_ACCESS at removeFromParentNode() SceneKitremoveFromParentNode() SceneKit 处的 EXC_BAD_ACCESS
【发布时间】:2016-06-02 11:15:33
【问题描述】:

我在游戏执行过程中随机弹出以下错误:

我正在随机创建一个 carNode 的多个实例,并且它们都具有从场景中删除节点的操作。大多数情况下这不是问题,但在某些情况下,应用程序会因照片中显示的错误而崩溃。在这些情况下,我似乎会得到错误:

对象未初始化 一个对象已经被释放 其他不太可能发生的事情

..除了第一个,我很确定我没有提前释放对象..那会是什么?

这是完整的代码:

func spawnCarAtPosition(position: SCNVector3) {

    // Create a material using the model_texture.tga image
    let carMaterial = SCNMaterial()
    carMaterial.diffuse.contents = UIImage(named: "assets.scnassets/Textures/model_texture.tga")
    carMaterial.locksAmbientWithDiffuse = false

    // Create a clone of the Car node of the carScene - you need a clone because you need to add many cars
    var carNode: SCNNode!
    let randomNumb = AppDelegate().randRange(0, upper: beachCarArray.count -     1)
    let selectedObject = beachCarArray[randomNumb]
    carNode = selectedObject.objectscene.rootNode.childNodeWithName(selectedObject.objectname, recursively: false)!.clone() as SCNNode
    carNode.name = selectedObject.objectname
    carNode.position = position

    // Set the material
    carNode.geometry!.firstMaterial = carMaterial

    // x = length, y = height, z = width
    let xscale = 0.6
    let yscale = 0.8
    let zscale = 0.5
    carNode.scale = SCNVector3(xscale, yscale, zscale)

    // Create a physicsbody for collision detection
    let boundingBox = AppDelegate().sizeOfBoundingBoxFromNode(carNode)
    let carPhysicsBodyShape = SCNPhysicsShape(geometry: SCNBox(width: CGFloat(boundingBox.width * Float(xscale)), height: CGFloat(boundingBox.height * Float(yscale)), length: CGFloat(boundingBox.depth * Float(zscale)), chamferRadius: 0.0), options: nil)

    carNode.physicsBody = SCNPhysicsBody(type: SCNPhysicsBodyType.Kinematic, shape: carPhysicsBodyShape)
    carNode.physicsBody!.categoryBitMask = PhysicsCategory.Car
    carNode.physicsBody!.collisionBitMask = PhysicsCategory.Player
    carNode.physicsBody?.contactTestBitMask = PhysicsCategory.Player

    // Move the car
    let moveDirection: Float = position.x > 0.0 ? -1.0 : 1.0
    let moveDistance = levelData.gameLevelWidth()
    let moveAction = SCNAction.moveBy(SCNVector3(x: moveDistance * moveDirection, y: 0.0, z: 0.0), duration: Double(AppDelegate().randomBetweenNumbers(6.0, secondNum: 7.0)))
    let removeAction = SCNAction.runBlock { node -> Void in
        node.removeFromParentNode()
    }
    carNode.runAction(SCNAction.sequence([moveAction, removeAction]))

    // Rotate the car to move it in the right direction
    if moveDirection > 0.0 {
        carNode.rotation = SCNVector4(x: 0.0, y: 1.0, z: 0.0, w: 3.1415)
    }

    // add node to screen
    rootNode.addChildNode(carNode)
}

编辑:

崩溃前的对象打印:

<SCNNode: 0x1374e5ba0 'BeachCar_2' pos(1.500000 0.035000 -4.800000) rot(0.000000 1.000000 0.000000 3.141500) scale(0.600000 0.800000 0.500000) | geometry=<SCNGeometry: 0x135fe80c0 'BeachCar_2'> | no child>

使用 SCNAnimation 删除操作:

编辑 2:

func createSpawnNode(gridPosition: SCNVector3, row: Int, parentNode: SCNNode)  {

        // Determine if the car should start from the left of the right
        let startCol = row % 2 == 0 ? 0 : data.columnCount() - 1
        let moveDirection : Float = row % 2 == 0 ? 1.0 : -1.0

        // Determine the position of the node
        var position = coordinatesForGridPosition(column: startCol, row: row)
        position = SCNVector3(x: position.x, y: GameVariables.gamePlaneHeight / 2, z: position.z)

        // Create node
        let spawnNode = SCNNode()
        spawnNode.position = position

        var spawnAction: SCNAction!
        var delayAction: SCNAction!

        // Create an action to make the node spawn cars
        spawnAction = SCNAction.runBlock({ node in
            self.spawnDelegate!.spawnCarAtPosition(node.position)
        })

        delayAction = SCNAction.waitForDuration(3.0, withRange: 2.0)
        spawnNode.runAction(SCNAction.repeatActionForever(SCNAction.sequence([spawnAction, delayAction])))

        parentNode.addChildNode(spawnNode)

        // record newly created node
        recordNodeAtRow(spawnNode, row: row)
    }

parentNode 是场景的根节点。

【问题讨论】:

    标签: scenekit


    【解决方案1】:

    推测...可能内部的某些东西持有对 carNode 的引用,该引用持续超过您的 removeFromParentNode() 调用?看起来有一个保留周期:carNode 拥有对 removeAction 的强引用,其闭包拥有(强?)对 carNode 的引用。

    不过,我认为SCNAction 上的removeFromParentNode 的存在是一个很大的暗示。如果不需要它就不会在那里。而不是基于闭包的调用,尝试

    let removeAction = SCNAction.removeFromParentNode()
    carNode.runAction(SCNAction.sequence([moveAction, removeAction]))
    

    只是为了确保:您是从主线程调用spawnCarAtPosition(),而不是后台线程,对吧?

    在 EDIT 2 之后进行编辑: createSpawnNode() 读起来有点混乱,因为您重用了position(两个let 定义而不是一个var 怎么样?)(另外两个var 定义会更直接let , 顺便提一句)。我没有看到任何我认为会导致崩溃的东西。

    我不会复制源 Car 的 objectName,而是给每个节点一个唯一的名称(可能是 NSDate().description),以查看您是否可以检测到模式。

    我还尝试将生成从 SCNAction 移出并进入渲染回调(可能是 renderer(_:updateAtTime:),以防您遇到内部 SceneKit 错误。您正在调用另一个 SCNAction。文档是对这是否允许保持沉默,但是由于您看到了不稳定的行为,因此简化似乎是一件好事。

    我假设您已经尝试过打开僵尸和设置异常断点的标准技巧。

    【讨论】:

    • 仍然崩溃,但出现不同的错误:0x190d06314 : ldr x8, [x9, #80]
    • 有趣。进行removeFromParent 调用时,是否有可能已经删除了carNode?还是从未连接过?我想知道如果在调用runAction() 之前将addChildNode() 调用移动一点会发生什么。
    • 好的,我试过了,但是好像没什么区别。它仍然会因第二个错误而崩溃。
    • 我们可以看看你是如何调用spawnCarAtPosition()的吗?
    • 似乎用 dispatch_async(dispatch_get_main_queue(),{ }) 包装对 spawn 函数的调用可以避免崩溃。您说嵌套操作可能会导致问题是完全正确的。
    猜你喜欢
    • 2021-11-29
    • 2018-05-13
    • 2016-03-12
    • 2021-05-10
    • 1970-01-01
    • 2022-11-26
    • 2019-04-07
    • 2012-05-06
    • 1970-01-01
    相关资源
    最近更新 更多