2017-04-11 15 views
2

所以我正在開發一個包含SpriteKit遊戲的應用程序。我注意到的是,之後我開始和關閉遊戲內存保持爲顯示在下面的圖中增加:SpriteKit在我離開遊戲後保留內存

enter image description here

我使用的是模態呈現呈現遊戲從視圖控制器。所以問題是: 有沒有辦法從內存中完全刪除場景?

我在點擊視圖控制器上的關閉按鈕來關閉它。 scene.quitGame()方法基本上釋放所有節點,動作等。在理想的世界中,我甚至不需要做任何這樣的事情,因爲將會有一個完全擺脫SKScene的魔法命令。

@IBAction func quit(_ sender: UIButton) { 
    scene.quitGame() 
    scene.removeFromParent() 
    self.removeFromParentViewController() 
    self.dismiss(animated: true, completion: nil) 
    scene = nil 
} 

編輯:目前我從viewDidLoad中現場用下面的代碼:

scene = GameScene(size: view.bounds.size) 
let skView = view as! SKView 
skView.showsFPS = false 
skView.showsNodeCount = false 
skView.ignoresSiblingOrder = true 
scene.scaleMode = .resizeFill 
if let heroImage2 = heroImage2, let myImage = myImage, let monsterImage = monsterImage{ 
    scene.addPicture(img: heroImage2, myImage: myImage,monsterImage: monsterImage, bigMonsterImage: bigMonsterImage!) 
} 
skView.presentScene(scene) 
scene.viewController = self 

編輯2 - 我註釋掉調用此方法包括重複永遠動作和泄漏似乎走走

func createHerosAction(duration: Double = 5.0){ 
     run(SKAction.repeatForever(
      SKAction.sequence([ 
       SKAction.run(addHero), 
       SKAction.wait(forDuration: duration) 
       ]) 
     ), withKey:"createHeros") 
    } 



func addHero() { 
    // Create sprite 
    if(heroImage == nil){ 
     heroImage = UIImage(named: "hero") 
    } 

    let Texture = SKTexture(image: heroImage!) 
    let hero = SKSpriteNode(texture:Texture) 
    hero.size.width = size.width * 0.17 
    hero.size.height = hero.size.width 
    hero.name = "hero" 
    hero.zPosition = 2 

    let heroSide = arc4random_uniform(2) 

    hero.physicsBody = SKPhysicsBody(rectangleOf: hero.size) // 1 
    hero.physicsBody?.isDynamic = true // 2 
    hero.physicsBody?.categoryBitMask = PhysicsCategory.Hero // 3 
    hero.physicsBody?.contactTestBitMask = PhysicsCategory.Projectile // 4 
    hero.physicsBody?.collisionBitMask = PhysicsCategory.None // 5 

    let actualY = random(min: size.height*0.3 + hero.size.height/2 + size.height * 0.12, max: size.height - hero.size.height/2 - size.height * 0.15) 

    let pointRightOfScreen = CGPoint(x: size.width + hero.size.width/2, y: actualY) 
    let pointLeftOfScreen = CGPoint(x: -hero.size.width/2, y: actualY) 

    if(heroSide == 0){ 
     hero.position = pointRightOfScreen 
    }else{ 
     hero.position = pointLeftOfScreen 
    } 

    addChild(hero) 

    let actualDuration = random(min: CGFloat(2.0), max: CGFloat(5.0)) 

    var actionMove = SKAction() 

    if(heroSide == 0){ 
     actionMove = SKAction.move(to: pointLeftOfScreen, duration: TimeInterval(actualDuration)) 
    }else{ 
     actionMove = SKAction.move(to: pointRightOfScreen, duration: TimeInterval(actualDuration)) 
    } 

    let numberOfUpsAndDown = random(min: CGFloat(1.0), max: CGFloat(10.0)) 
    let variance = random(min: CGFloat(-70.0), max: CGFloat(70.0)) 


    let mvHero = moveHeroUpAndDown(node: hero, variance: variance,duration: actualDuration/numberOfUpsAndDown) 

    let actionMoveDone = SKAction.removeFromParent() 


    let loseLifeAction = loseLife(node: hero) 

    hero.run(SKAction.sequence([actionMove, loseLifeAction, actionMoveDone]), withKey: "moveHero") 
    hero.run(mvHero, withKey: "UpAndDown") 


} 

編輯3:泄漏似乎是在這個SKAction被稱爲上面。我刪除這個動作後,泄漏停止了。

func loseLife(node: SKSpriteNode) -> SKAction{ 

    let loseALifeAction = SKAction.run(){ 

     if(self.gamePaused == false){ 
      self.playSound(fileName: "losesound.wav") 

      if(self.lives > 0){ 
       self.updateLives(newValue: self.lives - 1, lostLife: true) 
       //self.lives -= 1 
      } 

      print("lives: \(self.lives)") 

      if(self.lives <= 0){ 
       print("hit me") 
       node.run(self.loseGame()) 
      } 
     } 
    } 
    return loseALifeAction 
} 
+0

這個視圖控制器被反覆顯示和解僱?或者視圖控制器始終在運行?場景是否定義了視圖控制器正在設置的委託? –

+0

正在顯示和解除正在控制場景的視圖控制器。 –

+0

我沒有定義委託。這是如何運作的? –

回答

5

根據您的意見,您應該使用capture lists

func createHerosAction(duration: Double = 5.0){ 

     run(SKAction.repeatForever(
      SKAction.sequence([ 

       SKAction.run {[unowned self] in 
        self.addHero() 
       }, 
       SKAction.wait(forDuration: duration) 
       ]) 
     ), withKey:"createHeros") 
    } 

這是一個很大的話題,但我建議你開始閱讀我所發佈的鏈接,因爲它的一切詳細解釋從「ARC如何工作」,「什麼是捕獲列表」到弱和無主的關鍵字。我已經寫了幾次關於這個,以及在這個網站上的許多其他人,這是一個很大的話題,所以我會跳過這一次:)

+0

再次感謝您的所有驚人幫助@Whirlwind。這仍然不能解決我的問題,但我們正在關注它。請參閱編輯3. –

+0

@JPAquino我在我自己的項目中重新創建了它,並且您的'createHerosAction'使泄漏 - 意味着場景在轉換後無法釋放。那麼,通常的'SKTransition'。這就是爲什麼你需要[[無主]自己] ... ...我會研究你的新編輯...順便說一下,爲什麼你創建一個'UIImage',爲了創建'SKTexture'來創建'SKSpriteNode '從紋理?只需用'SKTexture(命名:)'即可。你甚至可以使用'SKSpriteNode(imageNamed:)',但該方法已被證明[不是那種性能](http://stackoverflow.com/a/30448038/3402095)... – Whirlwind

+0

@JPAquino嘗試把'[[無主的自我]「。你必須記住,當你在閉包中使用強自己時,閉包將捕獲自己。 – Whirlwind

0

我相信它的內部SpriteKit泄漏持有內存中的ViewController。我們發現SpriteKit在關閉viewController後似乎保留了Scene和SKView。

在我們的案例中,我們開始專門介紹遊戲結束後的一個零場景,在我們將遊戲展示在屏幕上之後。

// Remove the game scene to stop game code and free up memory 
    if let skView = view as? SKView { 
     skView.presentScene(nil) 
    } 
+0

似乎不適合我。我嘗試將它添加到遊戲場景中的quitGame()方法和viewController上的quit方法,但內存泄漏保持不變。 –

+1

presentScene(nil)只會在SKView上設置場景屬性爲零。如果其他一些場景對這個場景有很強的參考,那麼泄漏將會保留......當場景是當然是泄漏物體:) – Whirlwind

+0

你有沒有可以保留強烈引用「自我」的閉包?像在跑步(塊)行動等? – BadgerBadger