SKAction runAction不执行完成块

时间:2023-01-23 00:26:05

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

SKSpriteNode是SKNode的子节点,放置在SKSpriteNode数组中以用于存储目的。

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

使用动画删除此SKSpriteNode。在此动画结束时,执行完成块以执行某些语句...

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:

删除必须同时发生在SKSpriteNode父级和数组中。根据这两个删除的顺序,结果是否正确:

  • if SKSpriteNodeis deleted from 1/ the array then 2/ from the SKNode parent’s, the completion block is executed.
  • 如果从1 /数组中删除SKSpriteNode然后从SKNode父项删除2 /,则执行完成块。
  • if the inverse order, 1/ SKNode parent’s then 2/ the array, the completion block is not executed.
  • 如果是逆序,1 / SKNode父级则为2 /数组,则不执行完成块。

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:

现在,如果在从theGrid操作中删除removeFromParent之前,如下所示,则不会执行完成:

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 个解决方案

#1


11  

From the SKAction Reference:

来自SKAction参考:

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.

SKAction对象是由场景中的节点(SKScene)执行的动作......当场景处理其节点时,将评估与这些节点关联的动作。

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.

换句话说,当且仅当该节点在场景中时,才运行节点的动作。通过调用removeFromParent,从场景中删除节点,永远不会调用runBlock操作(因为节点不再在场景中),因此序列永远不会完成。由于序列没有完成,因此不会调用完成块。

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

为安全起见,我建议将removeFromParent调用移动到完成块。这样的事情感觉更安全:

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.

TL; DR序列未完成,因此序列的完成块不会被调用。

#1


11  

From the SKAction Reference:

来自SKAction参考:

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.

SKAction对象是由场景中的节点(SKScene)执行的动作......当场景处理其节点时,将评估与这些节点关联的动作。

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.

换句话说,当且仅当该节点在场景中时,才运行节点的动作。通过调用removeFromParent,从场景中删除节点,永远不会调用runBlock操作(因为节点不再在场景中),因此序列永远不会完成。由于序列没有完成,因此不会调用完成块。

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

为安全起见,我建议将removeFromParent调用移动到完成块。这样的事情感觉更安全:

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.

TL; DR序列未完成,因此序列的完成块不会被调用。