SpriteKit TileMapNode MemoryLeak Bug

Hello community,


after days and days of researching and trying out my best, i do not find a solution on my memory leak problem.

I load my GameScene.sks with this code like everyone else does:


extension SKNode {

  1. class func unarchiveFromFile(file:String) -> SKNode? {
  2.   if let path = Bundle.main.path(forResource: file, ofType: "sks") {
  3.      let url = URL(fileURLWithPath: path)
  4.           do {
  5.              let sceneData = try Data(contentsOf: url, options: .mappedIfSafe)
  6.              let archiver = NSKeyedUnarchiver(forReadingWith: sceneData)
  7. archiver.setClass(self.classForKeyedUnarchiver(), forClassName: "SKScene")
  8.              let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey)
  9.                   as! SKNode                        
  10.              archiver.finishDecoding()                   
  11.              return scene
  12.              }
  13.           catch { print(error.localizedDescription) return nil }
  14.     } else {
  15.        return nil
  16.     }
  17. }


and i am using it in my code here:


  1. func load(level: String) {
  2.      if let levelNode = SKNode.unarchiveFromFile(file: level) {
  3.      mapNode = levelNode
  4.      self.worldLayer.addChild(mapNode)
  5.      loadTileMap()
  6.      }
  7. }


If i comment out the line

self.worldLayer.addChild(mapNode)
everything works perfect and memory will never rise. But if i use it (i need it :D) memory keeps climbing and climbing.

With use of Instruments it says that the line with

let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! SKNode
causes all the memory leaks.

Unfortunately i do not get it managed to remove my leaks.


I appreciate all help.

>> With use of Instruments it says that the line with

let scene = […]
causes all the memory leaks.


No, that's not the cause of the leaks. That's the place where the leaked objects are created. Based on your code, the cause of the leak seems to be your "load" function. You add a new child of "worldLayer", but you don't remove it when moving to a new level. So, all of your levels exist in the scene at one time, and memory usage goes up. You need something like this:


func load(level: String) {
     if let levelNode = SKNode.unarchiveFromFile(file: level) {
          mapNode.removeFromParent () // discard the old level
          mapNode = levelNode
          self.worldLayer.addChild(mapNode)
          loadTileMap()
     }
}


If you are, in fact, removing the old level from "worldLayer" somewhere else, then the leak indicates you still have a reference to it somewhere in your code.

Hello and welcome to the forums.

>it says that the line with

let scene = archiver.decodeObject(forKey: NSKeyedArchiveRootObjectKey) as! SKNode
causes all the memory leaks
.


...only points to where the issue bubbled up, not it's root cause. Set break points and step thru your code to help isolate, and/or brush up on the process according to Apple via the Instruments User Guide 'Find Memory Leaks': https://developer.apple.com/library/content/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/FindingLeakedMemory.html


Speak up if more questions, and good luck.


Ken

Hello and thank you for your answer. I forgot to say that i already implemented removing the child and everything that belongs to it.


override func willMove(from view: SKView) {

mapNode.removeFromParent()

worldLayer.removeAllActions()

worldLayer.removeAllChildren()

worldLayer.removeFromParent()

mapNode = nil

worldLayer = nil

self.removeAllActions()

self.removeAllChildren()

self.removeFromParent()

}


But unfortunately this is not working for me. The leak still exists.


Setting `mapNode.removeFromParent ()` before initializing it cannot work because it will have nil. I tried it anyways and this was the expected result.

I don´t know why removing the child in `willMove` doesn´t do it for me.


Greetings

Apple still didn‘t reply to my bug report... :/

SpriteKit TileMapNode MemoryLeak Bug
 
 
Q