ios - swift 3 (SpriteKit) : Reseting GameScene doesn't deallocate

标签 ios swift sprite-kit skscene

我一直在尝试通过创建 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实例具有场景属性,场景具有 View 属性。当呈现场景时,这些属性会相应地自动设置(场景会感知其 View ,而 View 会感知新创建的场景)。

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

灰屏

由于场景已从 View 中删除,您现在看到的是灰色屏幕。这是 View 的默认颜色。所以,目前没有场景。你会说,但是怎么做呢?我做了:

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

好吧,代码并没有因为 optional chaining 而崩溃.一切都优雅地失败了(行未执行)。但现在你要说:

"Wait, I've seen deinit call!"



这是真的。但是你看到的是一个deinit调用newScene实例。那是因为上面的行失败了,新的场景没有出现,当前的方法到了最后,因为没有东西保留这个新的实例,它释放了。尽管如此,当前场景实际上并没有被释放,因为如果是这样的话,你会看到 两个 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呈现它。如果有东西保留它,它不会释放场景。假设您在 GameViewController 中做了一些愚蠢的事情, 并强烈引用了当前呈现的场景(我猜这不需要代码?)所以场景将保留到 GameViewController解除分配...意味着,当你这样做时:
presentScene(nil) 

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

此外,您可能有多个泄漏。泄漏的不是现场。您可以让其他对象泄漏,例如。对象 A 是场景的属性,对象 B 是场景的属性。对象 A 强烈指向对象 B,反之亦然。那就是强引用循环。现在场景将释放,但这两个对象将保留在内存中。

这就是为什么我在评论中建议在自定义类上覆盖 deinit 方法。

如何解决泄漏?

我将跳过对此的详细说明,因为那只是复制/粘贴 Apple 的文档,并且对 how to solve/prevent leaks 有很好的解释。 (个人和公寓示例)。但关键是,在可能相互保留的类中使用弱/无主引用。闭包也是如此。定义捕获列表并在场景保留 block 的情况下使用弱/无主自我,并且 block 保留场景。

对于那些对 presentScene(SKScene?) 更感兴趣的人方法,我在下面链接了一些来自技术说明的引用(我想知道为什么这样的信息不是 presentScene(SKScene?) 方法的文档的一部分)。

Technical Note 中有提及说的是:

SKView maintains a cache of the scenes it presents for performance reasons





Passing a nil argument to SKView presentScene does not cause the scene to be freed, instead, to release the scene, you must free the SKView that presented it.

关于ios - swift 3 (SpriteKit) : Reseting GameScene doesn't deallocate,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/41656740/

相关文章:

objective-c - SCNScene - 不渲染在 TouchBegan 处理程序上对 SKNode 进行的更改

ios - 向弓所面向的方向射箭

ios - FBSDKApplicationDelegate 没有名为 "application"的成员

ios - 嵌入了 containerView 的静态单元格上的动态高度

ios - 如何在 tableview 中显示姓名,就像在 iphone 联系人列表中一样,包含 A 到 Z 部分

ios - 我在将 uiview 当前位置设置为 uiview 默认位置时遇到问题?

ios - 应避免强制转换

ios - 查找触摸在路径上的位置(按百分比)

swift - Swift 4 中常量 '#selector' 的参数

ios - 向 SKSpriteNode 施加脉冲以赋予其随机方向