12

I created a simple game with SpriteKit, however every time I run the game, the memory usage in simulator increases about 30mb, but never decreases when the game is finished.

When I run the game over ten times the simulator gets slower and slower and eventually crashes.

In this simple game I have two controllers and a gamescene:

MainController calls GameViewController via a button triggered

In GameViewController, gamescene is initialised in this way:

class GameViewController: UIViewController
{

  var skView:SKView!

  var scene:GameScene!

  override func viewDidLoad() {

      super.viewDidLoad()
      scene = GameScene(size: view.bounds.size)
      skView = view as SKView
      skView.ignoresSiblingOrder = true
      scene.scaleMode = .ResizeFill

      scene.viewController = self
      skView.presentScene(scene)

  }

//with a prepareForSegue deinitialises the scene and skview:
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {

    if segue.identifier == "GameFinished"{

        scene.removeAllActions()
        scene.removeAllChildren()
        scene.removeFromParent()
        scene = nil

        skView.presentScene(nil)
        skView = nil

        let target = segue.destinationViewController as MainController
    }
  }
}

In the GameScene, viewController is a property

var viewController:GameViewController? = GameViewController()

the segue is triggered with this:

self.viewController!.performSegueWithIdentifier("GameFinished", sender: nil)

I've also tried putting remove methods into deinit in GameScene:

  deinit{
    self.removeAllActions()
    self.removeAllChildren()
  }

Still wouldn't work

Darvas
  • 974
  • 3
  • 14
  • 27
Fan Zhang
  • 240
  • 3
  • 9
  • Run Instruments and check for a memory leak. https://developer.apple.com/library/mac/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/InstrumentsQuickStart/InstrumentsQuickStart.html – sangony Jun 17 '15 at 13:21
  • I had this same issue not 30 minutes ago. It turned out I had a memory leak so I set my view and scene properties to weak, it removed the leak issue but I'm not sure if it's the best way to do it. – Andy Heard Jun 17 '15 at 13:55

2 Answers2

10

Your GameViewController has a strong reference to your GameScene. And your GameScene had a strong reference to your GameViewController. This leads to a strong reference cycle, which means that neither objects will be deallocated.

You need to declare your viewController property in your GameScene as weak.

weak var viewController:GameViewController? = GameViewController()
Epic Byte
  • 33,840
  • 12
  • 45
  • 93
  • OK, I used dismissViewControllerAnimated instead of performSegueWithIdentifier after the game is finished, without the removeAllChildren and removeAllActions methods, it seems "worked"... Memory increases with a very small amount each time the game is launched...How could this happen? – Fan Zhang Jun 24 '15 at 12:01
  • @FanZhang Could you explain how you did it? I am experiencing this same exact problem for a while now and I'm really hoping for a fix... – DHShah01 Jul 17 '15 at 16:43
  • Nothing special, just instantiate the GameViewController in GameScene: weak var viewController:GameViewController? = GameViewController() , and run self.viewController?.dismissViewControllerAnimated(true, completion: nil) when game is finished. – Fan Zhang Jul 20 '15 at 09:19
  • 1
    Thank you! My viewcontroller had a weak reference to the SKView already, but in my SKScene there was a strong reference to the viewcontroller it was in, by making that a weak var my memory usage went back down after popping. – CodyMace May 22 '16 at 23:12
  • Wow, this mad a huge difference! This should be marked as the correct answer to this question. – dbDev Mar 02 '19 at 21:31
0

Using Swift 3, Xcode 8 and iOS 10. After avoiding strong references, taken care of SKTextures, etc. memory level didn't recover after dismissing the scene and returning to the "menu" viewController. I was using:

override func sceneDidLoad() {...}

This is available in iOS 10 but I wanted iOS 8&9 compatibility that's why I've changed to the older:

override func didMove(to view: SKView) {...}

Beside getting compatible with older iOS versions, it turns out that the memory level drops after dismissing the scene. This was a surprise. I'm missing probably some leaks but it's working for me. I hope it helps someone.

user2888102
  • 147
  • 4
  • Can you create minimal verifiable example to prove this leak? – Whirlwind Nov 06 '16 at 08:34
  • @Whirlwind sorry I've tried, but I'm not able to do that. Leaks instrument shows a couple of leaks related to "SKAction.animate" that I've not solved yet. I though this was the problem, but now, only changing to "didMove" the memory issue is gone. – user2888102 Nov 06 '16 at 18:16