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:
SKSpriteNode
is deleted from 1/ the array then 2/ from the SKNode
parent’s, the completion block is executed.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}),
])
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With