切换场景SpriteKit

时间:2015-08-23 07:52:07

标签: swift memory sprite-kit

好一段时间回来测试我有一个没有错误的随机崩溃,我不知道为什么。所以我进行了分析,我想出了以下数据。 Data

因为看起来我的内存使用量越来越高,直到它变得更加严重。注意一般曲率的斜率在一开始是如何大于后来的。 (你可能会注意到这是我第一次进入并分析这类事情)。

现在游戏中发生的事情基本上是两个屏幕。 1.菜单:这个屏幕有很多纹理但除了有按钮玩游戏外什么也没做 2.游戏:它有纹理的TOOONS,并且具有大量的cpu使用,因为它是实际的游戏。 3.死亡:此屏幕有一个资产,它是一个允许您重放游戏的按钮。这不应该使用太多的内存或CPU。但它仍然有记忆。对我来说,无论“内存泄漏”是什么,这都会发出尖叫声。

如果你看一下图表,基本上游戏中发生了什么,菜单开始了,第一个秒杀加载了实际游戏,然后我就死了。然后,从那时起,我在游戏和死亡屏幕之间切换,每个尖峰都表示正在加载的游戏场景。

如果这个数据是我预测它的方式,你会在死机屏幕的一个非常小的内存使用之间振荡,然后返回游戏内存使用。

故事的道德是我很确定精灵套件在切换场景后没有正确清理,我需要知道为什么可能。

为了切换场景,我正在使用maxkargin详细说明的方法 here

顺便说一句我正在使用sprite kit和SKScenes以及SKSpriteNodes快速工作

非常感谢!

4 个答案:

答案 0 :(得分:3)

有几个原因,我的游戏遇到了类似的问题。如果你正确地执行它,则不需要删除诸如纹理之类的东西。删除每个场景上的纹理变化也不理想,您希望将它们保留在内存中以提高性能,这样就不必每次都重新加载它们。

这是一个基本清单,您可以使用它来查看是否创建了内存泄漏。

1)使用print语句将deinit方法添加到每个场景/类。如果deinit被调用你的场景正确解除分配。

 deinit {
    print("Deinit GameScene")
  }

2)您是否通过在2个类之间创建引用来创建强引用循环?

强大参考周期的经典Apple示例

 class Person {
    var dog: Dog?
  }

 class Dog {
   var person: Person?
 }

要修复它,你必须使这两个属性中的一个变弱

  class Person {
     var dog: Dog?
  }

  class Dog {
     weak var person: Person?
  }

使用期权的另一个好习惯是在不再需要时将它们设置为零。

 person = nil

也许请查看谷歌和Apple Swift文档,了解如何处理此问题。我前一段时间也问过类似的问题

Swift SpriteKit ARC for dummies

3)你在使用闭包吗?它们可能导致内存泄漏。

SpriteKit中更常见的情况是这两个示例可能/将导致内存泄漏并使您的场景无法解除分配。 (动作2是一个捕获自我的闭包)

 // Example 1
 let action1 = SKAction.wait(forDuration: 1)
 let action2 = SKAction.run(someMethod)
 let sequence = SKAction.sequence([action1, action2])
 run(SKAction.repeatForever(sequence))

 // Example 2
 let action1 = SKAction.wait(forDuration: 1)
 let action2 = SKAction.run {
      self.someMethod()
 }
 let sequence = SKAction.sequence([action1, action2])
 run(SKAction.repeatForever(sequence))

一个好的经验法则是,当编译器强制你使用self时,你很可能会在不使用弱/无主的情况下创建内存泄漏。

因此,要修复上述2个SKAction示例,您可以确保在更改场景或IMO时始终删除所有操作,更好的方法是将代码更改为此以避免首先造成内存泄漏。

 let action1 = SKAction.wait(forDuration: 1)
 let action2 = SKAction.run { [weak self] in
      self?.someClassMethod()
  }
 let sequence = SKAction.sequence([action1, action2])
 run(SKAction.repeatForever(sequence))

请注意以上所有例子中你也可以写

 .... { [unowned self] in

并且你不需要使用?在关闭

 self.someMethod()

当你使用无主的时,你基本上说自己永远不会是nil,如果在调用闭包时它实际上是nil会导致崩溃。如果你使用弱自我,你告诉编译器self在调用闭包之前可能会变为nil因此self是可选的以避免崩溃。

我认为使用“弱”而不是“无主”来避免这种情况几乎总是更好。在我的一个游戏中,我在封闭中使用了无主的自我,当它从iTunes中获取StoreKit产品时被调用。这导致了我的子弹崩溃,因为我可以在调用闭包之前退出SKScene。如果你使用弱自我,你就不会因为使用选项而崩溃。

希望这有点帮助

答案 1 :(得分:1)

sprite kit使用缓存来保持场景之间的perforemce,这就是为什么在场景之间切换时会占用内存,而且无论如何你都不会释放这个内存或者从场景中移除所有孩子或者[self.view presentScene:nil];他们是更好的解决方案...

仔细阅读本文

https://developer.apple.com/library/ios/qa/qa1889/_index.html

使用视图管理场景并从这些视图中删除SKView以在多屏幕游戏中保持记忆

答案 2 :(得分:0)

所以基于每个人都说这就是我所做的。在更改为新场景之前,我运行基本上接受所有纹理的函数,并使用sprite节点将它们设置为空构造函数,以便它们更小,然后删除所有操作和子项。这似乎可以解决问题!他们可能仍然存在其他内存问题,但在我确定之前,我需要仔细查看并调整一些内容。

感谢大家的建议!

答案 3 :(得分:0)

作为副菜的答案,我有一个复杂的场景,其中有很多自定义精灵工具包子类和动作一起交互,唯一阻止我的SKScene子类调用其deinit的东西是一位代表我忘了定义为weakunowned,这创造了一个经典的强参考周期问题。因此,如果您在场景设置中为自己分配了任何代表,请执行以下操作:

myCustomNode.delegate = self

然后检查委托的定义,它应该如下所示:

weak var delegate:MyCustomProtocol?

或者这个:

unowned var delegate:MyCustomProtocol?

如果您无法访问myCustomNode的源代码,请尝试将代理分配给场景中的nil,如下所示:

override function willMove(from view:SKView) {
    myCustomNode.delegate = self
}

此外,如果您收到错误

  

弱/无主只能应用于类和类绑定协议类型

这是因为您的自定义协议必须包含: class,如下所示:

protocol MyCustomProtocol : class {/*protocol definition here*/}