Swift SpriteKit ARC for dummies

时间:2016-03-04 14:28:06

标签: swift reference sprite-kit instruments cycle

我一直试图围绕强大的参考周期,我正在努力。我一直在阅读苹果和某些网站上的文档,我觉得他们并没有真正解决我的问题。

我知道你必须使用弱和无主,取决于对象是否可以为零。所以说你必须要有2个这样的课程

class Person {
   var dog: Dog?
  ....
}

class Dog {
  weak var person: Person?
}

相互引用我知道其中一个必须使用弱/无主。这是大多数教程中的经典示例。

我也看过这样的例子,对我来说也很有意义

class Person {

 unowned let gameScene: GameScene

 init(scene: GameScene) {
   self.gameScene = scene 
  ....
 }

我也明白,如果没有失效,NSTimers会导致强引用周期。我没有使用NSTimers所以这应该不是问题。

我进一步理解协议也可能导致内存泄漏,因此他们处理它们的方法是使其成为类协议

protocol TestDelegate: class { }

我尝试引用协议的地方使它成为弱属性

 class: SomeClass {

  weak var myDelegate: TestDelegate?

 }

最后我知道我正在捕捉自我的闭包

SKAction.runBlock { [unowned self] in
   self.player.runAction....
}

然而,当涉及到我的实际spritekit游戏时,我似乎在所有地方都有引用循环,即使对于简单的类,我肯定不会引用另一个类,我也不明白为什么。

所以我的主要问题是

1)是否所有属性都创建了强引用循环或仅创建了在初始化类之前创建的全局属性?

2)在我的简单类中,还有哪些其他东西可能会创建一个强大的参考周期?

例如,我使用的是创建平台的类

class Platform: SKSpriteNode {

 /// basic code to create platforms 
 /// some simple methods to rotate platforms, move them left or right with SKActions.

现在我有类似于Traps,Enemies等的类。再次,他们通常只设置精灵属性(物理体等)并有一些方法来动画它们或旋转它们。它们没有任何花哨的东西,尤其是在引用其他类或场景方面。

在我的gameScene中,我有一种创建平台的方法(对于敌人,陷阱等都是一样的)

func createPlatform() {

 let platform1 = Platform(.....
 platformNode.addChild(platform1)

 let platform2 = Platform(....
 platformNode.addChild(platform2)

 let platform3 = Platform(...
 platformNode.addChild(platform3)

 // platform node is just a SKNode in the gameScene to help maintain the difference zPositions of my objects.

}

当我运行分配时,我可以看到3个平台中只有1个进入瞬态状态,2当我更改为menuScene时保持持久性。奇怪的是,如果我改变顺序或创建/删除某些平台,总是只有1被删除。所以看起来他们正在创建强大的引用,除了1.因此,如果我重放我的关卡几次,我可以在内存中快速拥有50-100个持久性平台。因此,我的场景也没有得到更多的内存浪费。

我的另一个例子是

class Flag {
  let post: SKSpriteNode
  let flag: SKSpriteNode

  init(postImage: String, flagImage: String) {

       post = SKSpriteNode(imageNamed: postImage)
       ...


       flag = SKSpriteNode(imageNamed: flagImage)
       ...
       post.addChild(flag)
  }
}

同样的问题。我在我的场景中创建了一些标志,有时标志不会被删除,有时它会被删除。同样,这个类不引用任何场景或自定义类,它只是创建一个精灵并为其设置动画。

在我的场景中,我有一个标志的全局属性

 class GameScene: SKScene {

   var flag: Flag!

  func didMoveToView... 

 }

如果flag本身没有引用GameScene,为什么会创建一个强引用?我也不能用

weak var flag: Flag!

因为一旦标志初始化我就会崩溃。

这样做有什么明显的东西吗? 有没有一个很好的技巧在仪器中找到它们,因为它对我来说似乎很疯狂。 这让我很困惑,主要是因为我的课很简单,不会引用其他自定义类,场景,viewControllers等。

1 个答案:

答案 0 :(得分:2)

感谢您的所有答案,尤其是appzYourLift和您的详细回复。

我整天都在挖掘我的spriteKit项目,还经常试验游乐场,现在我的游戏完全无泄漏,没有找到强大的参考周期。

它实际上发现了我在仪器中看到的许多泄漏/持久性类别,因为其他东西没有解除分配。

似乎永远重复行动导致我的泄密。我所要做的就是遍历场景中的所有节点并删除它们的动作。

这个问题帮助了我这个

iOS 7 Sprite Kit freeing up memory

更新:我最近再次重新讨论这个话题,因为我觉得必须手动删除节点上的操作不应该是必要的,并且可能变得很麻烦。经过更多研究后,我发现了(我的)内存泄漏的确切问题。

这样的“SKAction永远重复”显然会导致泄密。

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

因此您需要将其更改为不会导致泄漏

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

这直接来自我提出的Apple错误报告。