5
votes

So I've read several questions on this but most are in Objective-C and I haven't found any that address/answer this directly. I am new to programming here so please explain any suggestions really thoroughly.

I need to understand how to deallocate my GameScene after game over is reached. The reason I need to do this is because after game over, I transition to a new SKScene (the game over scene) and when I transition back to my GameScene, either GameScene is not reset entirely or I'm generating a new GameScene each time.

I say this because My frames per second count goes down every time I get game over and transition back to the GameScene, so that if I do it enough times I can't even play the game anymore. This is a problem.

I don't understand why this happens because when I transition to my game over scene, I remove everything from my GameScene:

self.viewController!.performSegueWithIdentifier("goToGameOver", sender: nil)
            self.removeAllChildren()
            self.removeAllActions()
            self.scene?.removeFromParent()

I also read here: After Closing SKScene, Memory Remains High that removing the SKView that contains an SKScene deallocates the SKScene, so when both my GameScene and game over scenes are left, I remove BOTH views from their superviews like this:

override func viewDidDisappear(animated: Bool) {
        print("its gone")

        self.view.removeFromSuperview()

    }

But nothing has any affect on the decreasing frames per second count and the game keeps lagging. I don't understand what I'm not doing and can't tell whether the game over scene is the problem or I'm just not deallocating GameScene.

How do I deallocate the GameScene? What else should I be doing?

EDIT:

My node count and draws count remain about the same every time I transition back to GameScene, so that doesn't seem to be a problem. I tried testing whether deinit was called when transitioning between scenes (I didn't have a deinit before) using this within the GameScene class:

} //<**End of GAMESCENE**

    deinit {
        print("Deinit was called")
    } 

And nothing is printed so deinit is not being called.

EDIT 2:

@alex_p Here is what I have in my GameViewController-

class GameViewController: UIViewController, SKProductsRequestDelegate, SKPaymentTransactionObserver {

    var scene1: GameScene?
    var scene2: GameScene?
    var skView: SKView?

// Action to present next Scene
    @IBAction func nextSceneAction(sender: AnyObject) {
        print("Next scene")
        // Create new GameScene object
        scene2 = GameScene(fileNamed:"GameScene")
        // Present scene2 object that replace the scene1 object
        skView!.presentScene(scene2) //ERROR ON THIS LINE
        scene1 = nil
    }

And I call this method from my GameScene like this:

self.viewController.nextSceneAction(self)

I copied yours exactly but I am receiving the error unexpectedly found nil while unwrapping an Optional value on the line commented on above. Deinit in not being called.

1
You can start with overriding deinit in scenes. See if it is called when transitioning between scenes. That would be a start. If deinit isn't called, then you have to search for possible retain cycles. Also check nodes count and draws count. Can you update your question with those data ?Whirlwind
Just updated. I don't think deinit is being called so how does one search for a retain cycle?skyguy
Yeah, you have probably some strong references to the scene ... To start take a look at this : stackoverflow.com/questions/19251337/… . After that check out terms called "unowned self" and "weak self" stackoverflow.com/questions/24320347/… Hope this will take you somewhere.Whirlwind
Also if I recall correctly, showsNodesCount will show the number of nodes which are currently drawn, not the offscreen nodes. Offscreen nodes are not removed automatically and even if not drawn, they are still in there, in a node tree. This can cause a lag. You can try to enumerate through all nodes inside node three by passing this string //* as a node name. Read more here : stackoverflow.com/a/25749743/3402095Whirlwind

1 Answers

0
votes

In my project, I used the following mechanism and it worked well. All my scenes SKScene objects were optional variables. When i need the new scene to show, i create it and present at SKView. When i need to display the new scene, I set the previous object scene object to nil, this immediately reducing the reference count by 1, and becouse of at this moment no one object is not use my scene, the reference count becomes zero and scene was deleted.

The SKScene object is a ordinary class object and ARC works with them like with all reference type objects. You only need to monitor the number of references to the scene. All are finished with the various resources I was start in deinit of SKScene object

The simple example:

At UIViewController we have optional objects of GameScene:

class GameViewController: UIViewController {
    var scene1: GameScene?
    var scene2: GameScene?
    var skView: SKView?
    
    // Action to present next Scene
    @IBAction func nextSceneAction(sender: AnyObject) {
        print("Next scene")
        // Create new GameScene object
        scene2 = GameScene(fileNamed:"GameScene")
        // Present scene2 object that replace the scene1 object
        skView!.presentScene(scene2)
        scene = nil
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()

        // Create GameScene object
        scene = GameScene(fileNamed:"GameScene")
        skView = (self.view as! SKView)
        skView!.showsFPS = true
        skView!.showsNodeCount = true

        skView!.ignoresSiblingOrder = true
        
        scene!.scaleMode = .AspectFill
        
        // Present current scene
        skView!.presentScene(scene)
    }
}

At GameScene in deinit print some text to show that it object will be deleted:

class GameScene: SKScene {
   ...
    
    deinit {
        print("Deinit scene")
    }
}

Debug output after push the nextSceneAction button:

Next scene

Deinit scene