Chapter 15 v1.3 GameplayKit Leaks problems

Hi guys.

I’ve encountered several inconvenient related the StateMachines memory leaks for this chapter.

Trying to understand the problem I created a simple code that use one state. The GameScene is this:

import SpriteKit
import GameplayKit

class GameScene: SKScene {
   
   lazy var gameState:GKStateMachine = GKStateMachine(states: [Introduction(scene: self)])
   
   override func didMove(to view: SKView) {
  
  self.gameState.enter(Introduction.self)
   }
}

And the state is this one:

import SpriteKit
import GameplayKit

class Introduction: GKState {
   
   unowned let scene:GameScene
   
   init(scene:SKScene) {
      self.scene = scene as! GameScene
      super.init()
   }
   
   override func didEnter(from previousState: GKState?) {
      print("INSIDE THE Introduction STATE")
   }
}

The problem is that when I run the Leaks debugger, I received one leak as soon as I enter to the state. Does anybody has a suggestion?

I found this same problem with the game. Here I was trying to isolate in order to understand.

Ok. I have good news and bad news. First, the good news: changing the next line of code inside Introduction state:

unowned let scene:GameScene

For the next one:

weak var scene:GameScene?

Makes everything works. According to a lot of people this should not be happening. Nevertheless, it is.

Now, the BAD NEWS. If I decide to change GameScene to be other kind of Subclass, like this:

import SpriteKit
import GameplayKit

class GameScene: GameSceneHelper {
   
   lazy var gameState:GKStateMachine = GKStateMachine(states: [
      Introduction(scene: self),
      SecondState(scene: self) ])
   
   override func didMove(to view: SKView) {
      
      self.gameState.enter(Introduction.self)
   }
}

where GameSceneHelper is:

import SpriteKit
import GameplayKit

class GameSceneHelper: SKScene {
   override func didMove(to view: SKView) {
   }
}

Then nothing works. Not even the weak var. So if you have any suggestion to be apply to your code, I will really appreciate it.

Ok. After a lot of time doing this I found the source of the problem. The declaration of the gameState must be moved from GameScene to GameSceneHelper like this:

class GameSceneHelper: SKScene {
   var gameState:GKStateMachine!
   override func didMove(to view: SKView) {
   }
}

No use for the lazy var declaration inside GameScene. Then everything works.

I think this could be something to consider in the update of the book. StateMachines are a terrific tool, but you have to be careful about memory leaks.