SpriteKit 和 SwiftUI 动画(内存泄漏 - NSXPCConnection?) [英] SpriteKit and SwiftUI Animation (Memory Leak - NSXPCConnection?)

查看:30
本文介绍了SpriteKit 和 SwiftUI 动画(内存泄漏 - NSXPCConnection?)的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到了一个问题:在具有类似结构的更大项目中,我从仪器工具中获得内存泄漏.

如果你把它放在 Xcode 中并运行,你应该看到一条向右移动然后向左移动的线.当按下 Button 时,Line 跳转到定义的位置.如果您使用内存泄漏工具,点击按钮后会出现错误.我不知道为什么.这是一个错误吗?我在代码中有一个基本错误吗?如何避免这种情况?

这是将动画计算与 SwiftUI 连接起来的正确方法吗,我将 SKScene 作为 ObservableObject 并将动画标记为 @Published 以执行此动画?

感谢您的回答.

在泄漏工具中有一个注释,负责的框架是:

[NSXPCConnection remoteObjectProxyWithErrorHandler:]

感谢阅读,示例代码如下:概述

动画计算

 导入 SwiftUI导入 SpriteKit结构我的动画{var lenght:CGFloat = 0//行尾位置var up: Bool = true//如果线条向右或向左移动变异 func change(){自我提升?(长度 += 1) : (长度 -= 1)如果长度 >100{向上 = 假}否则如果长度<0{向上 = 真}}}

更新SKScene

<预><代码>类 GameScene:SKScene,ObservableObject{@Published var ani: MyAnimation//处理计算覆盖初始化(){ani = 我的动画()super.init(size: CGSize(width: 200, height: 100))}需要初始化?(编码器aDecoder:NSCoder){fatalError(init(coder:) 尚未实现")}覆盖 func 更新(_ currentTime:TimeInterval){ani.change()//计算新位置}}

内容视图

<预><代码>结构内容视图:查看{@StateObject var game = GameScene()var主体:一些视图{虚拟堆栈{ZStack{SpriteView(场景:游戏).不透明度(0)MyPath().environmentObject(游戏)}开始().环境对象(游戏)//按钮让线条跳到定义的位置}}}

动画路径

<预><代码>结构我的路径:查看{@EnvironmentObject var 游戏:GameScenevar body: 一些视图{路径{路径在path.move(to: CGPoint(x: 50, y: 50))path.addLine(to: CGPoint(x: 200 + game.ani.lenght, y: 220))//这里是 MyAnimation 结构的长度属性,应该导致重绘path.closeSubpath()}.stroke(颜色.黑色,线宽:4)}}

按钮

<预><代码>struct Start: View {//按钮@EnvironmentObject var 游戏:GameScenevar主体:一些视图{按钮(动作:{game.isPaused = 真game.ani.lenght = 30game.isPaused = 假}, 标签: {文本(开始")})}}

用于复制粘贴

 导入 SwiftUI导入 SpriteKit结构我的动画{var lenght:CGFloat = 0//行尾位置var up: Bool = true//如果线条向右或向左移动变异 func change(){自我提升?(长度 += 1) : (长度 -= 1)如果长度 >100{向上 = 假}否则如果长度<0{向上 = 真}}}类 GameScene:SKScene,ObservableObject{@Published var ani: MyAnimation//处理计算覆盖初始化(){ani = 我的动画()super.init(size: CGSize(width: 200, height: 100))}需要初始化?(编码器aDecoder:NSCoder){fatalError(init(coder:) 尚未实现")}覆盖 func 更新(_ currentTime:TimeInterval){ani.change()//计算新位置}}结构内容视图:查看{@StateObject var game = GameScene()var主体:一些视图{虚拟堆栈{ZStack{SpriteView(场景:游戏).不透明度(0)MyPath().environmentObject(游戏)}开始().环境对象(游戏)//按钮让线条跳到定义的位置}}}结构我的路径:查看{@EnvironmentObject var 游戏:GameScenevar body: 一些视图{路径{路径在path.move(to: CGPoint(x: 50, y: 50))path.addLine(to: CGPoint(x: 200 + game.ani.lenght, y: 220))//这里是 MyAnimation 结构的长度属性,应该导致重绘path.closeSubpath()}.stroke(颜色.黑色,线宽:4)}}struct Start: View {//按钮@EnvironmentObject var 游戏:GameScenevar主体:一些视图{按钮(动作:{game.isPaused = 真game.ani.lenght = 30game.isPaused = 假}, 标签: {文本(开始")})}}

解决方案

我可以使用以下代码重现相同的泄漏:

 导入 SwiftUI结构内容视图:查看{var主体:一些视图{虚拟堆栈{开始()}}}结构开始:查看{var主体:一些视图{按钮(动作:{}, 标签: {文本(开始")})}}

如果没有对这个问题有更深入的了解,我会假设您不对泄漏负责,但 Apple 是.

如果您仍然希望使用 SwiftUI,我认为您现在别无选择,只能忽略泄漏.
顺便说一下,我在使用 SwiftUI 时遇到了更严重的问题,我暂时放弃了它,因为我认为它还没有准备好.

I have a problem: In a bigger project with a similar structure I am getting a memory Leak from the Instrument Tool.

If you are putting this in Xcode and run, you should see a line which is moving to the right side and then to the left. When the Button is pressed, the Line jumps to a defined position. If you use the Memory Leak Tool there is an Error after the Button is tapped. I don't know why. Is this a bug? Do I have a basic mistake in the code? How to avoid this?

Is this the right way of connecting the animation calculation with SwiftUI, that I have the SKScene as an ObservableObject and mark the animation as @Published for doing this animation?

I appreciate any answers.

In the leakage Tool is a note, that the responsible frame is:

[NSXPCConnection remoteObjectProxyWithErrorHandler:]

Thanks for reading, here is the example code: Overview

Animation Calc

    import SwiftUI
    import SpriteKit

    struct MyAnimation{

        var lenght:CGFloat = 0  //Position of the line end
        var up: Bool = true  //if the line is moving to right or left

        mutating func change(){
        
            self.up ? (lenght += 1) : (lenght -= 1)
        
            if lenght > 100{
                up = false
            }else if lenght < 0{
                up = true
            }
        }
    }

SKScene for updating


    class GameScene: SKScene, ObservableObject{
    
        @Published var ani: MyAnimation  //handles the calculation
    
        override init(){
            ani = MyAnimation()
            super.init(size: CGSize(width: 200, height: 100))
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func update(_ currentTime: TimeInterval) {
            ani.change()  //new Position is calculated
        }
    }

Content View


    struct ContentView: View {
    
        @StateObject var game = GameScene()
    
        var body: some View {
            VStack{
                ZStack{
                    SpriteView(scene: game).opacity(0)
                    MyPath().environmentObject(game)
                }
                Start().environmentObject(game)  
                //Button to let the line jump to the defined position
        
            }
        }
    }

Path to animate


    struct MyPath: View{
        
        @EnvironmentObject var game: GameScene
        
        var body: some View{
            Path{ path in
                path.move(to: CGPoint(x: 50, y: 50))
                path.addLine(to: CGPoint(x: 200 + game.ani.lenght, y: 220))  
                //here is the length property of the MyAnimation struct and should cause the redraw

                path.closeSubpath()
            }
            .stroke(Color.black, lineWidth: 4)
        }
    }

Button


    struct Start: View {    //Button
        
        @EnvironmentObject var game: GameScene
        
        var body: some View {
            Button(action: {
                game.isPaused = true
                game.ani.lenght = 30
                game.isPaused = false
            }, label: {
                Text("Start")
            })
        }
    }

For Copy Paste

    import SwiftUI
    import SpriteKit

    struct MyAnimation{

        var lenght:CGFloat = 0  //Position of the line end
        var up: Bool = true  //if the line is moving to right or left

        mutating func change(){
        
            self.up ? (lenght += 1) : (lenght -= 1)
        
            if lenght > 100{
                up = false
            }else if lenght < 0{
                up = true
            }
        }
    }


    class GameScene: SKScene, ObservableObject{
    
        @Published var ani: MyAnimation  //handles the calculation
    
        override init(){
            ani = MyAnimation()
            super.init(size: CGSize(width: 200, height: 100))
        }
    
        required init?(coder aDecoder: NSCoder) {
            fatalError("init(coder:) has not been implemented")
        }
    
        override func update(_ currentTime: TimeInterval) {
            ani.change()  //new Position is calculated
        }
    }



    struct ContentView: View {
    
        @StateObject var game = GameScene()
    
        var body: some View {
            VStack{
                ZStack{
                    SpriteView(scene: game).opacity(0)
                    MyPath().environmentObject(game)
                }
                Start().environmentObject(game)  
                //Button to let the line jump to the defined position
        
            }
        }
    }


    struct MyPath: View{
        
        @EnvironmentObject var game: GameScene
        
        var body: some View{
            Path{ path in
                path.move(to: CGPoint(x: 50, y: 50))
                path.addLine(to: CGPoint(x: 200 + game.ani.lenght, y: 220))  
                //here is the length property of the MyAnimation struct and should cause the redraw

                path.closeSubpath()
            }
            .stroke(Color.black, lineWidth: 4)
        }
    }


    struct Start: View {    //Button
        
        @EnvironmentObject var game: GameScene
        
        var body: some View {
            Button(action: {
                game.isPaused = true
                game.ani.lenght = 30
                game.isPaused = false
            }, label: {
                Text("Start")
            })
        }
    }

解决方案

I could reproduce the same leak with the following code:

  import SwiftUI

  struct ContentView: View {
    var body: some View {
        VStack{
            Start()
        }
    }
  }

  struct Start: View {
    var body: some View {
        Button(action: {
        }, label: {
            Text("Start")
        })
    }
  }

Without having more insights into this issue, I would assume that you are not responsible for the leak, but Apple is.

I think you have no choice but to ignore the leak for now if you still wish to use SwiftUI.
By the way, I had worse issues with SwiftUI, and I have abandoned it for now because I believe it just isn't ready yet.

这篇关于SpriteKit 和 SwiftUI 动画(内存泄漏 - NSXPCConnection?)的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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