SKAction runAction does not execute completion block

别来无恙 提交于 2020-01-01 04:51:06

问题


A SKSpriteNode is child of a SKNode and is placed on an array of SKSpriteNode for storage purposes.

This SKSpriteNode is deleted using an animation. At the end of this animation a completion block is executed to perform some statements...

The deletion must occurred both in the SKSpriteNode parent’s and in the array. Depending on the order of these 2 deletions the result is correct or not:

  • if SKSpriteNodeis deleted from 1/ the array then 2/ from the SKNode parent’s, the completion block is executed.
  • if the inverse order, 1/ SKNode parent’s then 2/ the array, the completion block is not executed.

Why this behavior?

for position in listOfPositions {

   theSprite:SKSpriteNode = theGrid[position]

   /// the SKSpriteNode referenced by theSprite :
   /// - belongs to an array of SKSpriteNode: theGrid
   /// - belongs to a SKNode: theGameLayer
   ///
   /// In other words this SKSpriteNode is referenced twice
   ///

   let theActions = SKAction.sequence([
      /// Some actions here
      /// ...

      /// Remove theSprite from the Grid
      /// - position is an instance of a structure of my own
      /// - theGrid is accessed via a subscript
      ///
      SKAction.runBlock({self.theGrid[position] = nil}),

      /// remove theSprite from it's parent
      SKAction.removeFromParent(),
   ])

   theSprite.runAction(theActions,completion:{NSLog("Deleted")})
}

The completion message is displayed.

Now if removeFromParent is placed before the remove from theGrid action, as follow, the completion does not execute:

let theActions = SKAction.sequence([
   /// Some actions here
   /// ...

   /// remove theSprite from it's parent
   SKAction.removeFromParent(),

   /// remove theSprite from the Grid
   SKAction.runBlock({self.theGrid[position] = nil}),
])

回答1:


From the SKAction Reference:

An SKAction object is an action that is executed by a node in the scene (SKScene)...When the scene processes its nodes, actions associated with those nodes are evaluated.

In other words, the actions for a node is run if and only if that node is in the scene. By calling removeFromParent, you remove the node from the scene, the runBlock action is never called (since the node is no longer in the scene), and thus the sequence is never finished. Since the sequence doesn't finish, the completion block doesn't get called.

I would suggest moving the removeFromParent call to the completion block for safety's sake. Something like this feels safer:

for position in listOfPositions {

   let theSprite: SKSpriteNode = theGrid[position]

   /// the SKSpriteNode referenced by theSprite :
   /// - belongs to an array of SKSpriteNode: theGrid
   /// - belongs to a SKNode: theGameLayer
   ///
   /// In other words this SKSpriteNode is referenced twice
   ///

   let theActions = SKAction.sequence([
      /// Some actions here
      /// ...

      /// Remove theSprite from the Grid
      /// - position is an instance of a structure of my own
      /// - theGrid is accessed via a subscript
      ///
      SKAction.runBlock({self.theGrid[position] = nil})
   ])

   theSprite.runAction(theActions) {
      /// remove theSprite from it's parent
      /// Might need to weakly reference self here
      theSprite.removeFromParent(),
      NSLog("Deleted")
   }
}

TL;DR
The sequence doesn't complete, so the completion block for sequence doesn't get called.



来源:https://stackoverflow.com/questions/30599078/skaction-runaction-does-not-execute-completion-block

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!