I am currently developing a game where spheres are falling from the sky. While collecting spheres you gain points and after a certain amount of points all spheres accelerate to another speed.
- New spheres are continuously added to an Array (4 Spheres inside each SKNode).
- When they are to accelerate I iterate through the array to increase the speed of all of them.
- When the spheres have fallen out of the screen I remove them from the Array.
class GameScene: SKScene, SKPhysicsContactDelegate {
...
var allActiveNodes = Array<SKNode>()
private let concurrentNodesQueue = dispatch_queue_create(
"com.SphereHunt.allActiveNodesQueue", DISPATCH_QUEUE_CONCURRENT)
...
//1. This is where the new spheres are added to the Array via a new thread
func addSpheres(leftSphere: Sphere, middleLeftSphere: Sphere, middleRightSphere: Sphere, rightSphere: Sphere){
...
dispatch_barrier_async(self.concurrentNodesQueue){
self.allActiveNodes.append(containerNode)
let queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)
dispatch_async(queue) {
//Set the new spheres in motion
self.runPastAvatar(containerNode)
}
}
//2. This function starts a thread that will increase the speed of all active spheres
func increaseSpeed20percent(){
durationPercentage = durationPercentage * 0.8
dispatch_sync(self.concurrentNodesQueue){
let copyAllActiveNodes = self.allActiveNodes
let count = copyAllActiveNodes.count
for index in 0...count-1{
let node = copyAllActiveNodes[index]
node.removeAllActions()
self.runPastAvatar(node)
}
}
}
//3. This method removes the sphere that is not in screen anymore from the Array
func removeLastNode(node: SKNode){
dispatch_barrier_async(self.concurrentNodesQueue){
self.allActiveNodes.removeAtIndex(0)
node.removeFromParent()
println("Removed")
}
}
I am not sure if I have understood GCD correctly, I have tried multiple solutions and this is the one I was sure was going to work. I always end up with the same error message:
*** Terminating app due to uncaught exception 'NSGenericException',
reason: '*** Collection <__NSArrayM: 0x17004c9f0> was mutated while being enumerated.'
How do I get the threads to not interfere with each other while handling the array?
My problem was that I was using a thread-sleep solution to fire new spheres in a time interval. This was a bad choice but should not have produced such an error message in my opinion. I solved it using NSTimer to fire new spheres in a time interval. This gave the game a bit of a lag, but it is more robust and won't crash. Next up is finding out how to use the NSTimer without creating such a lag in the game!