简体   繁体   中英

GCD running background thread in spritekit

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.

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!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM