Swift SpriteKit 异步/等待错误:Swifts 新并发和 SpriteKit 的内存错误

发布于 2025-01-09 17:07:15 字数 858 浏览 1 评论 0原文

我们注意到在 SpriteKit run 函数中使用 async wait 时。

自我保留直到运行操作完成,这可能导致内存泄漏。

 Task {
            try? await Task.sleep(nanoseconds: 2 * NSEC_PER_SEC)
            await controller.startIntro()
            print("intro done")
        }

如果释放控制器,则在等待未完成之前不会释放内存。

呼叫:  scene.removeAllActions()

导致内存泄漏。

以下是项目重现步骤以及可能的解决方法:

https://github.com/maradic/SpriteKitConcurrencyBug

这是 SpriteKit 错误还是我做错了什么?

原始苹果论坛帖子:

https://developer.apple.com/forums/thread/701295

We noticed when using async await with SpriteKit run function.

Self is retained until run action is completed which can cause memory leak. 

 Task {
            try? await Task.sleep(nanoseconds: 2 * NSEC_PER_SEC)
            await controller.startIntro()
            print("intro done")
        }

If you deallocate controller, memory won't be released until await is not completed. 

calling:
scene.removeAllActions()

cause memory leak. 

Here is project reproducing steps with possible workarounds: 

https://github.com/maradic/SpriteKitConcurrencyBug

Is this SpriteKit bug or am I doing something wrong?

Original apple forum post:

https://developer.apple.com/forums/thread/701295

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

儭儭莪哋寶赑 2025-01-16 17:07:15

嗯,我想这里一切正常。这就是 await 的工作原理。它等待其async朋友完成。你有这样的:

Task {
        try? await Task.sleep(nanoseconds: 2 * NSEC_PER_SEC)
        await controller.startIntro()
        print("intro done")
    }

这可能会造成潜在的强循环,因为所有变量都隐式保留在该块内。只有当Task完成时,变量才会被释放。如果你更好地观察你的 secondWorkAround() 方法,你会发现通过在前两秒返回,保留周期仍然会发生(好吧,视图控制器将一直处于活动状态,直到 SKAction 没有结束)。因为你的行动是有限的,这不是什么大事。但想象一下,如果你有一些永远运行的序列。

这应该用 [weakcontroller] in 来解决,并且在您实现该操作(加上删除特定操作)之后,您将看到控制器在 sleep 完成后立即解除分配(在2 秒)。

另外,执行诸如 scene.removeAllActions() 之类的操作是行不通的。原因 您要删除在场景上运行的操作,而不是在其节点上运行的操作。因此,当您返回到上一个屏幕时,任务并不会结束。

现在你的 firstWorkAround() ,好吧,它相当黑客:)我不会这样做。它加速了场景,因此从 startIntro() 方法以异步方式运行的操作结束,任务完成。

但我不会那样做,这不是工作的方式。要点是您等待 startIntro() 的操作完成。如果它“自然”完成,或者如果你停止它,就会发生这种情况。合法的方法是找到按键操作并停止它。

请注意,您也有类似的东西:

 scene.enumerateChildNodes(withName: "//*") { (node, _) in
            node.removeAllActions()
 }

这将递归地遍历每个节点并删除它的操作。您可以在此处阅读更多信息。希望这有点道理,并且有帮助。

Well I guess everything here works normally. That is how await works. It waits for its async friend to finish. You have this:

Task {
        try? await Task.sleep(nanoseconds: 2 * NSEC_PER_SEC)
        await controller.startIntro()
        print("intro done")
    }

This can make potentially a strong cycle cause all variables are implicitly retained inside that block. Only when Task is completed, variables will be released. If You observe better Your secondWorkAround() method, You will see that by going back in first two seconds, a retain cycle will still occur (well, view controller will be alive until SKAction doesn't end). Cause Your action is finite, thats not a biggie. But imagine if You had some sequence that runs forever.

That should be solved with [weak controller] in and after You implement that (plus remove the specific action), You will see that controller deallocates immediately after sleep is finished (after 2 seconds).

Also, doing something like scene.removeAllActions(), won't work. Cause You are removing actions that are running on scene, not on its nodes. Thus, task doesn't end when You get back to previous screen.

Now Your firstWorkAround(), well its quite hackish :) I wouldn't do that. It speeds up a scene, thus action that is run in async way from Your startIntro() method gets ended, and task is finished.

But I wouldn't go that way, it's not how is meant to work. Point is that You await the action from startIntro() to finish. That will happen if it finishes "naturally", or if You stop it. And legit way would be to find action by key and to stop it.

Note that You have something like this too:

 scene.enumerateChildNodes(withName: "//*") { (node, _) in
            node.removeAllActions()
 }

This will go recursively trough every node and remove actions for it. You can read more here. Hope this makes sense a bit, and it helps.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文