Swift 用于假人的快速SpriteKit圆弧

Swift 用于假人的快速SpriteKit圆弧,swift,reference,sprite-kit,instruments,cycle,Swift,Reference,Sprite Kit,Instruments,Cycle,我一直试图把我的脑袋绕在强引用周期上,我在挣扎。我一直在阅读苹果和一些网站上的文档,我觉得他们并没有真正解决我的问题 我知道你必须使用弱和无主,这取决于对象是否为零。假设你必须上两门课 class Person { var dog: Dog? .... } class Dog { weak var person: Person? } SKAction.runBlock { [unowned self] in self.player.runAction.... } 我知道

我一直试图把我的脑袋绕在强引用周期上,我在挣扎。我一直在阅读苹果和一些网站上的文档,我觉得他们并没有真正解决我的问题

我知道你必须使用弱和无主,这取决于对象是否为零。假设你必须上两门课

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

class Dog {
  weak var person: Person?
}
SKAction.runBlock { [unowned self] in
   self.player.runAction....
}
我知道其中一个必须使用弱/无主。这是大多数教程中看到的经典示例

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

class Person {

 unowned let gameScene: GameScene

 init(scene: GameScene) {
   self.gameScene = scene 
  ....
 }
我还了解,如果不失效,NSTimer可能导致强引用循环。我没有使用NSTimer,所以这应该不是问题

此外,我还了解到协议也会导致内存泄漏,所以处理它们的方法是将其作为类协议

protocol TestDelegate: class { }
在我试图引用协议的地方,使其成为弱属性

 class: SomeClass {

  weak var myDelegate: TestDelegate?

 }
最后我知道了闭包,在这里我像这样捕捉自我

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

class Dog {
  weak var person: Person?
}
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.
现在我有类似的类,如陷阱,敌人等。他们通常只是设置精灵属性(物理体等),并有一些方法来设置它们的动画或旋转它们。它们没有什么奇特之处,特别是在引用其他类或场景时

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

当我运行分配时,我可以看到3个平台中只有1个进入瞬态,2个在我切换到menuScene时保持持久。奇怪的是,总是只有1个被删除,无论我是否更改订单或创建/删除一些平台。因此,他们似乎在创建强引用,除了1。因此,如果我重放几次我的级别,我可以很快在内存中拥有50-100个持久性平台。因此,我的场景也没有得到Denit,这是更多的内存浪费

我举的另一个例子是

class Flag {
  let post: SKSpriteNode
  let flag: SKSpriteNode

  init(postImage: String, flagImage: String) {

       post = SKSpriteNode(imageNamed: postImage)
       ...


       flag = SKSpriteNode(imageNamed: flagImage)
       ...
       post.addChild(flag)
  }
}
同样的问题。我在我的场景中创建了一些旗帜,有时旗帜不会被移除,有时会被移除。同样,该类不引用任何场景或自定义类,它只创建一个精灵并为其设置动画

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

 class GameScene: SKScene {

   var flag: Flag!

  func didMoveToView... 

 }
如果标志本身不引用游戏场景,为什么会创建一个强引用?。我也不能用

weak var flag: Flag!
因为一旦国旗被初始化,我就会崩溃

在做这件事时,我是否有明显的遗漏? 在乐器中找到它们有什么好办法吗?因为我觉得这太疯狂了。 这让我很困惑,主要是因为我的类非常简单,不引用其他自定义类、场景、视图控制器等。

所有属性都创建强引用循环还是只创建在初始化类之前创建的全局属性? 对对象的每个强引用都可能成为强引用循环的一部分。可能是

  • 强大的存储属性
  • 强局部/全局变量/常量
  • 我的意思是,它没有被宣布为弱小或无主

    事实上,如果在给定时刻存在从对象到对象本身的强引用路径,则会创建循环,并且ARC不会释放循环中所有对象的内存

    在我的简单类中,还有什么其他东西可以潜在地创建一个强引用循环? 没什么好说的了。当对象
    A
    对对象
    B
    有强引用时。。。它对
    a有很强的引用
    你有一个很强的引用循环

    一些建议:

    跟踪去初始化过程 只需向类中添加一个去初始化器,并在控制台上检查您的对象是否在您期望的时候被去初始化

    class Foo: SKSpriteNode {
        deinit {
            print(String(self))
        }
    }
    
    让SpriteKit管理强引用 避免场景图中节点之间的强引用。使用
    SKNode
    类提供的方法和计算属性来检索其他节点,如

    .scene
    .parent
    .childNodeWithName(...)
    .childrean
    

    这种方法可能会导致一些性能问题,但您应该首先更正代码,然后尝试提高性能。

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

    我一整天都在钻研我的spriteKit项目,也在操场上做了很多实验,现在我的游戏完全没有泄漏,没有很强的参考循环

    事实上,我在仪器中看到了很多泄漏/持久性类,它们仅仅是因为其他东西并没有释放

    我的泄密似乎是因为我一直在重复行动。我所要做的就是遍历场景中的所有节点并移除它们的动作

    这个问题对我有帮助

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

    像这样的“动作永远重复”显然会导致泄漏

    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))
    

    这直接来自于我做的一份苹果bug报告。

    并不是所有类都会导致引用周期,只是取决于它们如何相互引用,从而导致这种情况发生。在我正在进行的一个项目中,我遇到了没有发布的代码。我所做的是在每个类中添加一个deinit{print(“NameOfClass”)},这样我就可以计算出