これが私が得ているエラーです、詳細については添付の写真をチェックしてください。
com.Apple.scenekit.scnview-renderer(17):EXC_BAD_ACCESS(code = 1、address = 0xf000000010a10c10)
次の関数を呼び出すと、このエラーを再現できますが、この関数が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
}
}
}
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レンダリングループの正しい時間/スレッドで変更が発生します。