用于假人的 Swift SpriteKit ARC [英] Swift SpriteKit ARC for dummies

查看:17
本文介绍了用于假人的 Swift SpriteKit ARC的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在努力思考强大的参考周期,但我正在苦苦挣扎.我一直在阅读来自苹果和一些网站的文档,我觉得它们并没有真正解决我的问题.

I have been trying to wrap my head around strong reference cycles and I am struggling. I have been reading the documentation from apple and on some website and I feel like they dont really address my issues.

我知道你必须使用 weak 和 unowned ,这取决于对象是否可以为 nil.所以说你必须有2个这样的课程

I understand you have to use weak and unowned depending if the object can be nil or not. So say you have to 2 classes like this

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

class Dog {
  weak var person: Person?
}

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

that reference each other I know that one of them has to use weak/unowned. This is the classic example seen in most tutorials.

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

I also have seen examples like this and they too make sense to me

class Person {

 unowned let gameScene: GameScene

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

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

I also understand that NSTimers can cause strong reference cycles if not invalidated. I am not using NSTimers so this should not be a problem.

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

I furthermore understand that protocols can cause memory leaks too, so they way to handle them would be to make it a class protocol

protocol TestDelegate: class { }

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

and where I am trying to reference the protocol make it a weak property

 class: SomeClass {

  weak var myDelegate: TestDelegate?

 }

最后我知道了像这样捕获自我的闭包

And finally I know about closures where I am capturing self like this

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

然而,当谈到我实际的 spritekit 游戏时,我似乎到处都有引用循环,即使是简单的类,我也肯定不会引用另一个类,我不明白为什么.

However when it comes to my actual spritekit game I seem to have reference cycles all over the place, even for simple classes I am sure dont reference another class, and I dont understand why.

所以我的主要问题是

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

1) Do all properties create strong reference cycles or only global properties that are created before a class is initialised?

2) 还有哪些其他因素可能会在我的简单类中创建强引用循环?

2) What other things could potentially create a strong reference cycle in my simple classes?

例如我正在使用一个创建平台的类

For example I am using a class that creates platforms

class Platform: SKSpriteNode {

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

现在我为 Traps、Enemies 等提供了类似的类.同样,它们通常只是设置精灵属性(物理体等)并有一些方法来设置它们的动画或旋转它们.它们没有什么特别之处,尤其是在引用其他类或场景方面.

Now I have similar classes like this for Traps, Enemies etc. Again they normally just set the sprite properties (physics body etc) and have some methods to animate them or rotate them. There is nothing fancy going on in them, especially in regards to referencing other classes or scenes.

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

In my gameScene I have a method to create platforms (would be same for enemies, traps etc)

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 个进入瞬态状态,当我切换到 menuScene 时,2 个保持持久状态.奇怪的是,总是只有 1 被删除,如果我更改顺序或创建/删除某些平台都没关系.所以看起来他们正在创建强引用,除了 1.所以如果我重播我的关卡几次,我可以很快在内存中拥有 50-100 个持久平台.因此,我的场景也没有得到 deinit,这会浪费更多的内存.

When I am running allocations I can see that only 1 of the 3 platforms goes into transient state, 2 stay persistent when I change to my menuScene. Whats strange is that always only 1 gets removed, doesnt matter if I change the order or create/delete some platforms. So it seems they are creating strong references, except 1. So if I replay my level a few times I can quickly have 50-100 persistant platforms in memory. My scene therefore also doesn't get deinit which is more memory wasted.

另一个例子是

class Flag {
  let post: SKSpriteNode
  let flag: SKSpriteNode

  init(postImage: String, flagImage: String) {

       post = SKSpriteNode(imageNamed: postImage)
       ...


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

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

and same problem. I create some flags in my scenes and sometimes a flag doesnt get removed, sometimes it does. Again this class does not reference any scene or custom class, it merely creates a sprite and animates it.

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

In my scene I have a global property for flag

 class GameScene: SKScene {

   var flag: Flag!

  func didMoveToView... 

 }

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

Why would this create a strong reference if flag itself doesnt reference the GameScene?. Also I can't use

weak var flag: Flag!

因为一旦标志被初始化,我就会崩溃.

because I get a crash once the flag gets initialised.

执行此操作时我是否缺少明显的东西?在 Instruments 中找到它们是否有一个好技巧,因为这对我来说似乎很疯狂.它只是让我感到困惑,主要是因为我的类非常简单,并且没有引用其他自定义类、场景、viewControllers 等.

Is there something obvious I am missing when doing this? Is there a good trick to find them in Instruments because it seems madness for me. It just confusing to me mainly because my classes are quite simple and dont reference other custom classes, scenes, viewControllers etc.

推荐答案

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

Thank you for all the answers, especially appzYourLift and your detailed reply.

我整天都在研究我的 spriteKit 项目,还对游乐场进行了很多试验,我的游戏现在完全没有泄漏,没有找到强大的参考周期.

I was digging into my spriteKit project the whole day, also experimenting with playground a lot and my game is totally leak free now with no strong reference cycles to be found.

事实证明,我在仪器中看到的很多泄漏/持久类只是因为其他东西没有释放而存在.

It actually turned out a lot of the leaks/persistant classes I was seeing in instruments where simply there because something else didnt deallocate.

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

Its seems that repeat action forever was causing my leaks. All I had to do is loop through all the nodes in my scene and remove their actions.

这个问题帮助了我

iOS 7 Sprite Kit 释放内存

更新:我最近再次访问了这个主题,因为我觉得不必手动删除节点上的操作,并且可能会变得很麻烦.经过更多研究,我找到了(我的)内存泄漏的确切问题.

UPDATE: I recently revisited this topic again because I felt like having to manually remove actions on nodes should not be necessary and could become cumbersome. After more research I found the precise issue for the (my) memory leaks.

这样的SKAction 永远重复"显然会导致泄漏.

Having a "SKAction repeat forever" like this apparently causes the leak.

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

所以你需要把它改成这样才不会导致泄漏

So you need to change it to this to not cause a leak

 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 错误报告.

This is coming directly from an Apple bug report I made.

这篇关于用于假人的 Swift SpriteKit ARC的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆