Reputation: 13
I have this problem when I am running a background thread that uses "self" to look for variables with specific names. The project crashes and says that I cant make any enumerations on the "NSArray" which I searched up, and found out that is a list of all the objects in the scene which can't be edited. So I made this dummy project to show my problem in a simpel way.
Here is the code:
import SpriteKit
import Foundation
class GameScene: SKScene{
override func sceneDidLoad() {
}
var boxArray = [String]()
var boxNumber = 1
func addBox(){
var box = SKSpriteNode()
box.size = CGSize(width: 100, height: 100)
box.color = SKColor.red
box.position = CGPoint(x: 0, y: 0)
box.name = "box\(boxNumber)"
self.addChild(box)
boxArray.append(box.name!)
boxNumber += 1
}
func moveBox(){
for i in boxArray{
if self.childNode(withName: "\(i)") != nil{
var box = self.childNode(withName: "\(i)") as! SKSpriteNode
box.position.x += 10
}
}
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
addBox()
}
override func update(_ currentTime: TimeInterval) {
DispatchQueue.global(qos: .background).async {
self.moveBox()
}
}
}
Here is the crash report
2021-05-07 20:06:12.568267+0200 threading[99375:16974860] Metal GPU Frame Capture Enabled 2021-05-07 20:06:12.568677+0200 threading[99375:16974860] Metal API Validation Enabled IPHONE 2021-05-07 20:06:18.951497+0200 threading[99375:16975092] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x283018060> was mutated while being enumerated.' *** First throw call stack: (0x18d09d9d8 0x1a1406b54 0x18d09d39c 0x1bf463c90 0x1bf463480 0x1bf462ecc 0x1bf462e10 0x102fcc50c 0x102fcca08 0x102fcca4c 0x103733ce4 0x103735528 0x1037471e4 0x103747970 0x1d5743568 0x1d5746874) 2021-05-07 20:06:18.954714+0200 threading[99375:16975088] *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x283018060> was mutated while being enumerated.' *** First throw call stack: (0x18d09d9d8 0x1a1406b54 0x18d09d39c 0x1bf463c90 0x1bf463480 0x1bf462ecc 0x1bf462e10 0x102fcc380 0x102fcca08 0x102fcca4c 0x103733ce4 0x103735528 0x1037471e4 0x103747970 0x1d5743568 0x1d5746874) libc++abi.dylib: terminating with uncaught exception of type NSException *** Terminating app due to uncaught exception 'NSGenericException', reason: '*** Collection <__NSArrayM: 0x283018060> was mutated while being enumerated.'
So the function "moveBox" is being ran in the background thread which is all fine and it works. But by making a new SKSpritenode I will have made a change in the NSArray by inserting a new element, therefor the app crashes.
So my question is how can I make a new SKSpriteNode, use the background thread and call a node from "self" all the same time without the app crashing? I appreciate all the help i can get.
Upvotes: 0
Views: 118
Reputation: 101
Hello Nawab Hussaunnawab, the problem is not that you used DispatchQueue in your box, but because you put it in the function:
function update (_ currentTime: TimeInterval) {}
This function is already performed in the background. As defined by Apple, ** is called by the system exactly once per frame **, which is very fast. This function is never good for creating something, it works more like a getter, you should never define anything, in this example you showed, you are adding 10 more in the starting position, it is defining this number in each frame, I believe you don't want that. So this function would serve, for example: Only to obtain the position of the box when it moves
I hope it helps, anything just calls!
Upvotes: 0