繁体   English   中英

Swift 3(SpriteKit):重置GameScene不会取消分配

[英]Swift 3 (SpriteKit): Reseting GameScene doesn't deallocate

我一直在尝试通过创建有效的GameScene的新副本来重置GameScene。 但是,问题在于场景没有取消分配,这绝对是一个问题,因为我使用“分配”对应用程序进行了配置,并发现内存在“阻塞”和“堆积”。 这是我的GameViewController和GameScene的代码:

import UIKit
import SpriteKit
import GameplayKit

var screenSize = CGSize()

class GameViewController: UIViewController {

override func viewDidLoad() {
    super.viewDidLoad()
    if let view = self.view as! SKView? {
        // Load the SKScene from 'GameScene.sks'
        if let scene = SKScene(fileNamed: "GameScene") {
            // Set the scale mode to scale to fit the window
            scene.scaleMode = .aspectFill
            screenSize = scene.size     
            // Present the scene
            view.presentScene(scene)
        }

        view.ignoresSiblingOrder = true

        view.showsFPS = true
        view.showsNodeCount = true
    }
}

然后我的GameScene基本上是:

import SpriteKit
import GameplayKit

class GameScene: SKScene, SKPhysicsContactDelegate {
//Declare and initialise variables and enumerations here

deinit{print("GameScene deinited")}

override func didMove(to view: SKView) {
     //Setup scene and nodes
}

override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    //Do other things depending on when and where you touch

    //When I want to reset the GameScene 
    let newScene = GameScene(size: self.size)
    newScene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
    newScene.scaleMode = self.scaleMode
    let animation = SKTransition.fade(withDuration: 1.0)
    self.view?.presentScene(newScene, transition: animation)
}

永远不会打印“ GameScene deinited”,因此场景永远不会取消分配。

使用新问题进行编辑:通过使用我实际想要显示的场景更新场景之前,我提出了一个nil场景,从而解决了场景不会取消分配的问题。 但是,即使随后我展示新场景,现在屏幕仍保持空白。 这是我现在想要重置GameScene时的代码:

self.view?.presentScene(nil)
let newScene = GameScene(size: self.size)
newScene.anchorPoint = CGPoint(x: 0.5, y: 0.5)
newScene.scaleMode = self.scaleMode
let animation = SKTransition.fade(withDuration: 1.0)
self.view?.presentScene(newScene, transition: animation)

有人知道如何解决此问题吗?

感谢您的任何答复和帮助。

关于presentScene(SKScene?)方法

当您调用此方法时,根据传递给它的内容,会发生不同的事情……但是首先要注意的是……在场景由SKView呈现之前,您有一个新创建的场景和一个SKView实例。 SKView实例具有scene属性,而一个场景具有view属性。 呈现场景时,将相应地自动设置这些属性(场景会意识到其视图,而视图会意识到新创建的场景)。

现在,当您调用presentScene(nil) ,当前场景将从视图中删除,因此它的view属性自动变为nil( SKView实例上的场景属性也变为nil)。

灰屏

因为场景已从视图中删除,所以您现在看到的是灰色屏幕。这是视图的默认颜色。 因此,当前没有场景。 您将要说,但是如何? 我做了:

self.view?.presentScene(newScene, transition: animation)

好吧,该代码并没有因为可选的链接而崩溃。 一切都正常失败(未执行行)。 但是现在您将要说:

“等等,我已经看到了deinit电话!”

确实如此。 但是您看到的是对newScene实例的deinit调用。 这是因为上面的行失败了,并且没有显示新场景,并且当前方法到达了结尾,并且因为没有任何东西保留这个新实例,所以它会重新分配。 尽管如此,当前场景实际上并没有被释放,因为如果是这种情况,您将看到两个 deinit调用。

您可以通过以下方法检查已释放的实例(检查内存地址):

 deinit{
      print("deinit : \(self) has address: \(Unmanaged.passUnretained(self).toOpaque())")
    }

如果你要打印出self.viewself.presentScene(nil)线,你会看到self.viewnil 并且因为您使用的是可选链接,所以所有操作都会正常失败。 如果更改self.view!.presentScene(newScene)你将有崩溃大喊关于寻找一个nil ,同时展开可选。

调用presentScene(nil)无法解决泄漏

调用此方法,只需将场景属性在呈现它的SKView上设置为nil SKView 如果保留了某个场景,它将不会取消分配场景。 假设你在做你的一些愚蠢GameViewController ,并提出了有力的参考,以当前呈现(我想没有必要为这个代码吗?),所以现场将被保留,直到现场GameViewController重新分配...意义,当你这样做:

presentScene(nil) 

什么都不会发生。 场景的deinit将不会被调用。 请记住,此方法只是在呈现场景的SKView场景属性设置为nil,但是如果这不是对当前正在处理的场景的最后强引用,则不会取消分配场景(这就是ARC的工作方式)。

此外,您可能会多次泄漏。 泄漏的不是现场。 您可能有其他对象泄漏,例如。 对象A是场景的属性,而对象B是场景的属性。 对象A强烈指向对象B,反之亦然。 那是很强的参考周期。 现在场景将取消分配,但是这两个对象将保留在内存中。

这就是为什么我在注释中建议重写自定义类上的deinit方法的原因。

如何解决泄漏?

我将不再赘述,因为那仅仅是复制/粘贴Apple的文档,并且有关于如何解决/防止泄漏的很好的解释(Person&Apartment示例)。 但是重点是,在可能相互保留的类中使用弱/无主引用。 闭包也一样。 定义捕获列表,并在场景保留块的情况下使用弱者/无主的自己,而块保留场景。

对于那些对presentScene(SKScene?)方法更感兴趣的人,下面有一些我引用的技术说明中的引号(我想知道为什么这样的信息不属于presentScene(SKScene?)方法的文档)。

技术说明中提到:

出于性能方面的考虑,SKView会保留所呈现场景的缓存

将nil参数传递给SKView presentScene不会导致场景被释放,相反,要释放场景,必须释放呈现它的SKView。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM