2016-08-04 12 views
0

Ich muss die Spielszene freigeben, nachdem der Spieler ein Level beendet hat, so dass der Speicher verfügbar ist, um ein anderes Level meines Spiels zu laden. Wenn ich das nicht mache, stürzt meine App wegen Speicherproblemen ab.Swift, SpriteKit: Eine Gamescene freischalten und eine neue zuweisen

Ich habe die Hinweise dort gegeben gefolgt:

Swift: Deallocate GameScene after transition to new scene?

Aber leider ist es für mich nicht funktioniert. Ich erhalte eine Fehlermeldung „Could not Wert‚UIView‘gegossen‚SKView‘in meiner GameViewController Klasse Hier ist meine ganze 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() 
    } 
} 

ich die verschiedenen Funktionen aufrufen nextSceneAction1(), nextSceneAction2() und nextSceneAction3() von meinen anderen Klassen mit :

let controller1 = GameViewController() 
controller1.nextSceneAction1() 

oder

let controller2 = GameViewController() 
controller2.nextSceneAction1() 

Wenn die neue Szene geladen wird, bekomme ich diesen Fehler: „Kann nicht Wert vom Typ‚UIView‘gegossen "SKView". Weißt du, was mit diesem Code falsch ist?

Übrigens bin ich offen mit allen anderen Möglichkeiten, alte Szene aus dem Speicher zu löschen, bevor Sie eine neue laden, so dass es während der Lebensdauer der App keinen Speicherabsturz gibt.

Antwort

2

Im Allgemeinen wird die Zuordnung einer SKScene automatisch aufgehoben, sobald Sie zu einer neuen Szene übergehen, es sei denn, Sie haben ein Speicherleck. Daher müssen Sie in der Regel nichts tun, um Speicher freizugeben.

Um zu sehen, ob Ihre Szene, die Sie hat ausgeplant

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

die deinit Methode hinzufügen können, wenn diese Methode, wenn Sie Szenen, die Sie wissen alles richtig ausgeplant ändern aufgerufen wird, wenn es Sie nicht ein Gedächtnis haben genannt Bekommt Leck.

Auch Sie Code ist fehlerhaft, Sie erstellen eine neue GameViewController-Instanz jedes Mal, wenn Sie Szene ändern, anstatt auf die aktuelle Instanz zuzugreifen.

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

Sie normalerweise nur Ihre erste Szene aus Ihrem GameViewController laden und als alle anderen Szene Änderungen direkt in der SKScene getan werden kann, sind Sie in. Kümmern Sie sich nicht die GameViewController für diese Verwendung.

In Ihrem aktuellen SKScene können Sie auf eine neue Szene wie folgt ändern (zB von GameScene zu 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

+0

Dank hilft, so scheint es, alle Texturen aus den spritesheets bleiben jedoch in Speicher, auch wenn die Szene vom Bildschirm verschwunden ist. Es ist mir gelungen, die Speicherauslastung zu reduzieren, indem ich alle meine 2040X2048-Texturen durch eine sehr kleine PNG-leere Textur von 160 Bytes von 10X10 Pixeln ersetze. Dies reduziert den Speicherverbrauch meines Spiels von mehreren hundert MB, wenn eine Szene verschwunden ist und durch eine neue ersetzt wurde ... – PGibouin

+0

Dies ist normales Verhalten. SpriteKit speichert die Textur für die Performance. Ich würde sie nicht freigeben, lass SpriteKit es für dich tun. – crashoverride777

+0

Um hinzuzufügen. Gehen Sie zu Ihren SKScenes und fügen Sie die Methode demin (siehe aktualisierte Antwort) mit einer print-Anweisung hinzu.Wenn deinit angerufen wird, weißt du, dass die ganze Szene korrekt freigegeben wurde, wenn du kein Speicherleck hast. Auf diese Weise ist es einfacher zu sehen, was passiert, weil SpriteKit viele Dinge im Hintergrund erledigt, z. B. das Textur-Caching. – crashoverride777