3

Apple states in https://developer.apple.com/documentation/spritekit/skscenedelegate :

Modifying SpriteKit objects outside of the ordained callbacks (a background queue or anything else non-main-thread) can result in concurrency related problems. Even dispatching work on the main thread asynchronously or at a later time is risky because the closure is likely to be done outside of the timeframe SpriteKit expects. If you're experiencing a segmentation fault or other type of crash occurring deep within the SpriteKit framework, there's a good chance your code is modifying a SpriteKit object outside of the normal callbacks.

I'm using gesture recognizers to interact with my sprite kit objects. A simple example would be to add a SKAction to a node when the user tapped an object:

func tapAction(gr:UITapGestureRecognizer) {
    scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
}

Despite the fact that this "just works" for the moment, I'm afraid that this does not work in more complicated cases.

Is there any hint from Apple that this is allowed? Or do I really have to defer the modification of the SpritKit object from the gesture action to an ordained callback?

Klaas
  • 22,394
  • 11
  • 96
  • 107
  • you are safe, you are just assigning an action, that is going to run during the normal sprite kit updates – Knight0fDragon Jul 13 '17 at 13:12
  • this seems totally normal to me. Except the force unwrap is problematic if your balloon gets popped or something :P I would feel wary if this gesture removed or changed physicsBodies (because that always causes issues in didBegin) in which case having this set a flag that will be interpreted in your gamescene may be ideal. – Fluidity Jul 13 '17 at 13:41
  • @Fluidity the "balloon" gets never removed. I know how to handle optionals :-) – Klaas Jul 13 '17 at 14:33
  • haha ok, I didn't click on your name so I didn't know if your rep was from like java or something.. :P – Fluidity Jul 13 '17 at 14:35

1 Answers1

5

It looks like you are safe, you are just assigning an action. That is going to run during the normal sprite kit updates

if you were manipulating the actual object, or removing a node, you would come into problems. Let's say you tap to remove a node. This tap happens right before didContactBegin. didContactBegin would expect a node, but alas, you removed it, so it will crash.

If you want to feel safe about this, then set up a queue to fire at the beginning of your update.

class GameScene : SKScene
{
   public typealias Closure = ()->()
   public var processOnUpdate = [Closure]()


   override func update(_ currentTime: TimeInterval) {
       proceseOnUpdate.forEach{$0()}
       processOnUpdate = [Closure]()
       ....//do other stuff
   }
}

//SKView Code
func tapAction(gr:UITapGestureRecognizer) {
    scene.processOnUpdate.append(
    { 
       scene.childNode(withName: "balloon")!.run(SKAction.fadeOut(withDuration: 2))
    }}

}

My apologies if this does not run the first time, I am not on a Mac now to test this.

Knight0fDragon
  • 16,609
  • 2
  • 23
  • 44