web-dev-qa-db-ja.com

SceneKitレンダラー「EXC_BAD_ACCESS(コード= 1、アドレス= 0xf000000010a10c10)」を解決するにはどうすればよいですか?

これが私が得ているエラーです、詳細については添付の写真をチェックしてください。

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

エラーのログは次のとおりです。 More Info about the error

次の関数を呼び出すと、このエラーを再現できますが、この関数が1秒間に何度も呼び出された場合に限ります。これは、ユーザーがボタンをすばやくタップして次の利用可能な車に自転車で移動した場合に発生します。

ご覧のとおり、問題を解決するために、これをDispatchQueueでラップしてみました。

また、cycleCarNext()関数が終了したかどうかを追跡するためにBoolalreadyCyclingCarsを作成してから、再度呼び出すことができるようにしました。

この関数は基本的に、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
            }
        }
    }
12
Pat Trudel

SCNSceneRendererDelegate デリゲートメソッドの外部でSceneKitのシーングラフを変更(ノードの追加/削除など)しようとすると、この種のエラーが発生するのは私の経験です。

60 fpsでレンダリングを実行しているスレッドと、レンダリング対象からノードを削除する別のスレッド(メインスレッドなど)があるとします。ある時点で、レンダリングしているものが他のスレッドによって削除されると、レンダリングスレッドはレンダリングの途中になります。これは、EXC_BAD_ACCESSが発生します。シーンが変更される回数が多いほど、この競合が発生する可能性が高くなります。したがって、ボタンのマッシングによって問題がより簡単に再現される可能性があります。

修正は、SCNSceneRendererDelegateデリゲートメソッドの1つでのみシーンを変更することです。私は次のようなものを試してみます...

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のデリゲートもどこかに設定する必要があるでしょう(例; sceneView.delegate = self

cycleCarNextブール値はメインスレッドですぐに設定されますが、シーンは変更されないという考え方です。代わりに、SceneKitレンダリングループの正しい時間/スレッドで変更が発生します。

6
lock