Swift - GCD可变数组多线程问题"在枚举时发生突变"

时间:2015-02-25 20:45:31

标签: multithreading swift grand-central-dispatch mutated

我目前正在开发一种球体从天而降的游戏。在收集球体时,你获得积分,在一定数量的点之后,所有球体都会加速到另一个速度。

  
      
  1. 新的球体不断添加到阵列中(每个SKNode内部有4个球体)。
  2.   
  3. 当他们要加速时,我会遍历数组来提高所有数据的速度。
  4.   
  5. 当球体掉出屏幕时,我将它们从阵列中移除。
  6.   
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")
            }
    }

我不确定我是否正确理解了GCD,我尝试了多种解决方案,这是我确定要工作的解决方案。我总是得到同样的错误信息:

*** Terminating app due to uncaught exception 'NSGenericException', 
reason: '*** Collection <__NSArrayM: 0x17004c9f0> was mutated while being enumerated.'

如何让线程在处理数组时不会相互干扰?

2 个答案:

答案 0 :(得分:0)

我不确定这是否是问题,但是来自以下文件:

func dispatch_sync(_ queue: dispatch_queue_t,
             _ block: dispatch_block_t)
  

与dispatch_async不同,不对目标执行保留   队列。因为对此函数的调用是同步的,所以它“借用”   来电者的参考。而且,没有执行Block_copy   块。

     

<强>&GT;作为优化,此函数调用当前的块   尽可能的线程。

我把重要的部分加在了这里。为什么不用dispatch_barrier_sync来调用循环。

答案 1 :(得分:0)

我的问题是我使用线程睡眠解决方案在一个时间间隔内发射新球体。这是一个糟糕的选择,但在我看来不应该产生这样的错误信息。我使用NSTimer解决了它在一个时间间隔内发射新球体。这给游戏带来了一点滞后,但它更强大并且不会崩溃。接下来是找出如何使用NSTimer而不会在游戏中造成这样的延迟!