2016-05-09 27 views
0

我有一个for循环执行动画,然后完成删除它们,我试图在完成时调用另一个方法。这是我的代码:For循环在swift似乎随机选择增量

func animateMatch(completion:() ->()) { 
    var movingShape = level.shapeAtColumn(pointsContainingShapeArray[0].Column, row: pointsContainingShapeArray[0].Row) 
    let destinationShape = level.shapeAtColumn(pointsContainingShapeArray[0].Column, row: pointsContainingShapeArray[0].Row) 

    for everyShape in 1..<pointsContainingShapeArray.count { 
     movingShape = level.shapeAtColumn(pointsContainingShapeArray[everyShape].Column, row: pointsContainingShapeArray[everyShape].Row) 

     let Duration: NSTimeInterval = 1 

     let moveShapes = SKAction.moveTo((destinationShape?.sprite!.position)!,duration: Duration) 
     moveShapes.timingMode = .EaseOut 

     movingShape?.sprite?.runAction(moveShapes, completion: { 
      movingShape?.sprite?.removeFromParent() 
      print("Removed shape \(everyShape)") 
      if everyShape == pointsContainingShapeArray.count { 
       completion() 
      } 
     }) 

    } 
} 

基本上这个想法是,所述第一位置之后的阵列中的每个的形状移动到第一个的位置,然后从场景中删除。这工作正常,但我的完成每次都随机调用。所以最后我在那里添加了打印语句。这里是输出:

Removed shape 3 
Removed shape 1 
Removed shape 4 
Removed shape 2 

在这一点上,我非常沮丧,我决定是时候堆栈溢出。我无法弄清楚这里发生了什么。谢谢你的帮助!

这里是调用此方法的代码:

func handleSwipe(move: Move) { 
    view.userInteractionEnabled = false 

    level.performMove(move) 

    scene.animateMove(move) { 
     self.view.userInteractionEnabled = true 
     if hasMatch { 
      self.view.userInteractionEnabled = false 

      self.scene.animateMatch() { 
       self.scene.addNewSpritesForShapes(pointsContainingShapeArray) 
       hasMatch = false 
       self.view!.userInteractionEnabled = true 

      } 

     } 

    } 

} 
+0

'runAction'是一个异步操作。这是表现得如预期。 :p – Moritz

+0

关于我应该如何设置这个以我想要的方式工作的任何想法? – SomeGuy

+0

您可以使用'dispatch_apply'按顺序运行循环及其块。我相信还有很多其他的选择:使用NSOperations,只有在A完成后才使用回调来启动B等。 – Moritz

回答

2

问题不在于for循环,它的运行动作的异步特性。

当您调用moveShapes操作时,它在异步调用完成回原线程之前运行。这可以以任何顺序发生。您可以通过调用同步打印看到自己:

for everyShape in 1..<pointsContainingShapeArray.count { 
    print("Synchronous loop: \(everyShape)") 
} 

我想你会更好使用dispatch_group_t你最终完成:

func animateMatch(completion:() ->()) { 
    var movingShape = level.shapeAtColumn(pointsContainingShapeArray[0].Column, row: pointsContainingShapeArray[0].Row) 
    let destinationShape = level.shapeAtColumn(pointsContainingShapeArray[0].Column, row: pointsContainingShapeArray[0].Row) 
    // HERE 
    let group = dispatch_group_create() 
    dispatch_group_notify(group, dispatch_get_main_queue(), completion) 
    // 
    for everyShape in 1..<pointsContainingShapeArray.count { 
     // HERE 
     dispatch_group_enter(group) 
     // 
     movingShape = level.shapeAtColumn(pointsContainingShapeArray[everyShape].Column, row: pointsContainingShapeArray[everyShape].Row) 

     let Duration: NSTimeInterval = 1 

     let moveShapes = SKAction.moveTo((destinationShape?.sprite!.position)!,duration: Duration) 
     moveShapes.timingMode = .EaseOut 

     movingShape?.sprite?.runAction(moveShapes, completion: { 
      movingShape?.sprite?.removeFromParent() 
      print("Removed shape \(everyShape)") 
      // HERE 
      dispatch_group_leave(group) 
      // 
     }) 

    } 
} 
+0

我编辑了答案,以显示在所有操作完成时如何使用分派组获得通知。注意你的原始代码w /加入'// HERE'标记 – Logan

+0

非常感谢!这真的很有帮助....但是我仍然得到相同的结果。那次打印了2,1,3,4 ......我很抱歉,如果我听起来无知,我仍然对此感到陌生,而且我确信你可以通过我的代码告诉我,我还不是很好。 – SomeGuy

+0

这一行的完成:'moveShape?.sprite?.runAction(moveShapes,completion:{'将始终以未确定的顺序执行,我们不能在那里指定顺序,但我们可以做的是使用dispatch_group在我们调用完整的'completion'之前,我们必须等待所有的操作完成,另一种选择是在开始下一个序列之前等待该函数的完成 – Logan