2016-05-09 26 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