1
votes

I need to deallocate gamescene after the player have finished a level so that the memory is available to load another level of my game. If I don't do that, I have a crash of my app because of memory issues.

I have followed the indications given there:

Swift: Deallocate GameScene after transition to new scene?

But unfortunately, it doesn't work for me. I get an error "Could not cast value 'UIView' to 'SKView' in my GameViewController class. Here is my whole code:

import Foundation
import UIKit
import SpriteKit

class GameViewController: UIViewController {

    var scene1: SKScene?
    var scene2: SKScene?
    var scene3: SKScene?
    var skView: SKView?


    func nextSceneAction1() {

        scene2 = nil
        scene3 = nil

        skView! = self.view as! SKView
        skView!.showsFPS = true
        skView!.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView!.ignoresSiblingOrder = true

        scene1 = TransitionSigns(size: skView!.frame.size)
        scene1!.size.width = 2048
        scene1!.size.height = 1536


        /* Set the scale mode to scale to fit the window */
        scene1!.scaleMode = .AspectFill

        let transition = SKTransition.revealWithDirection(.Right, duration: 2)

        scene1!.scaleMode = .AspectFill
        skView!.presentScene(scene1!, transition: transition)
    }

    func nextSceneAction2() {

        scene1 = nil
        scene3 = nil

        let skView = self.view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true

        scene2 = TransitionSigns(size: skView.frame.size)
        scene2!.size.width = 2048
        scene2!.size.height = 1536


        /* Set the scale mode to scale to fit the window */
        scene2!.scaleMode = .AspectFill

        let transition = SKTransition.revealWithDirection(.Right, duration: 2)

        scene2!.scaleMode = .AspectFill
        skView.presentScene(scene2!, transition: transition)
    }

    func nextSceneAction3() {

        scene1 = nil
        scene2 = nil

        let skView = self.view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true

        scene3 = TransitionSigns(size: skView.frame.size)
        scene3!.size.width = 2048
        scene3!.size.height = 1536


        /* Set the scale mode to scale to fit the window */
        scene3!.scaleMode = .AspectFill

        let transition = SKTransition.revealWithDirection(.Right, duration: 2)

        scene3!.scaleMode = .AspectFill
        skView.presentScene(scene3!, transition: transition)
    }


    override func viewWillLayoutSubviews() {
        // Configure the view.

        let skView = self.view as! SKView
        skView.showsFPS = true
        skView.showsNodeCount = true

        /* Sprite Kit applies additional optimizations to improve rendering performance */
        skView.ignoresSiblingOrder = true

        let scene = MainView(size: skView.frame.size)
        scene.size.width = 2048
        scene.size.height = 1536

        /* Set the scale mode to scale to fit the window */
        scene.scaleMode = .AspectFill

        skView.presentScene(scene)
    }

    override func shouldAutorotate() -> Bool {
        return true
    }

    override func supportedInterfaceOrientations() ->   UIInterfaceOrientationMask {
        if UIDevice.currentDevice().userInterfaceIdiom == .Phone {
            return UIInterfaceOrientationMask.AllButUpsideDown
        } else {
            return UIInterfaceOrientationMask.All
        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Release any cached data, images, etc that aren't in use.
    }

    override func prefersStatusBarHidden() -> Bool {
        return true
    }


    override func viewDidLoad() {
        super.viewDidLoad()

    }

    override func viewDidDisappear(animated: Bool) {

        self.view.removeFromSuperview()
    }

    override func viewWillDisappear(animated: Bool){
        self.view.removeFromSuperview()
    }
}

I call the different functions nextSceneAction1(), nextSceneAction2(), and nextSceneAction3() from my other classes with:

let controller1 = GameViewController()
controller1.nextSceneAction1()

or

let controller2 = GameViewController()
controller2.nextSceneAction1()

When the new scene is loaded, I get this error: "Could not cast value of type 'UIView' to 'SKView'. Do you know what is wrong with this code?

By the way, I'm open with all other possibilities to clean old scene from memory before loading a new one so that there is no memory crash during the life of the app.

1

1 Answers

3
votes

In general a SKScene automatically deallocates once you transition to a new scene, unless you have a memory leak, so usually you don't have to do anything in particular to free memory.

To see if your scene has deallocated you can add the deinit method

  func deinit {
      print("scene did deallocate")
  }

If this method gets called when you change scenes you know everything correctly deallocated, if it doesn't get called you have a memory leak.

Also you code is faulty, you are creating a new GameViewController instance everytime you change scene instead of accessing the current instance.

 let controller2 = GameViewController() // creates new instance of GameViewController
 controller2.nextSceneAction1()

You normally only load your 1st scene from your GameViewController and than all other scene changes can be done directly in the SKScene you are in. Don't bother using the GameViewController for this.

In your current SKScene you can change to a new scene like this (e.g from GameScene to MenuScene)

 class GameScene: SKScene {

      ...


       func loadMenuScene() {

           let menuScene = MenuScene(size: self.size) // use size of current scene          
           let transition = Some SKTransition
           view?.presentScene(menuScene, withTransition: transition)
      }  
 }

Hope this helps