【发布时间】:2016-06-18 07:58:57
【问题描述】:
我一直在努力思考强大的参考周期,但我正在苦苦挣扎。我一直在阅读来自苹果和一些网站的文档,我觉得它们并没有真正解决我的问题。
我知道你必须使用 weak 和 unowned ,这取决于对象是否可以为 nil。所以说你必须有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 等提供了类似的类。同样,它们通常只是设置精灵属性(物理体等),并有一些方法来为它们设置动画或旋转它们。它们没有什么特别之处,尤其是在引用其他类或场景方面。
在我的游戏场景中,我有一种创建平台的方法(对于敌人、陷阱等都是一样的)
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,这会浪费更多的内存。
另一个例子是
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...
}
如果标志本身不引用 GameScene,为什么会创建一个强引用?我也不能用
weak var flag: Flag!
因为一旦标志被初始化,我就会崩溃。
执行此操作时我是否缺少明显的东西? 在 Instruments 中找到它们是否有一个好技巧,因为这对我来说似乎很疯狂。 它只是让我感到困惑,主要是因为我的类非常简单,并且没有引用其他自定义类、场景、viewControllers 等。
【问题讨论】:
-
并非所有类都会导致引用循环,这仅取决于它们如何相互引用导致这种情况发生。在我正在进行的一个项目中,我遇到了未发布的代码。我所做的是为每个类添加一个 deinit { print("NameOfClass") },这样我就可以计算出什么被释放了,什么没有被释放。这很耗时。还要始终确保如果您使用任何委托,这些属性总是很弱。
-
即使这是一个有趣的话题,你也应该一一提问。真的很难回答和涵盖你所有的问题,尤其是没有完全可行的例子来重现所描述的行为。您应该专注于一个特定问题(例如,为什么没有正确释放平台对象)就像其他人指出的那样,有一些方法/最佳实践可以遵循,当然您可以使用 Instruments (Leaks),但真正的代码仍然是需要一个准确的答案。
标签: swift reference sprite-kit instruments cycle