swift 如何解除RealityKit ARView()的分配?

fjaof16o  于 2022-12-17  发布在  Swift
关注(0)|答案(1)|浏览(127)

我无法从内存中释放RealityKit ARView()
我知道ARKit + SceneKit也有类似的问题,解决方法如下:https://stackoverflow.com/a/53919730/7826293这并没有解决我的问题,不幸的是。
上面的解决方案是通过手动删除所有“可疑”的东西来工作的。这正是我在更广泛的范围内所做的:

class ViewController_ARViewMemoryTest: UIViewController {

    var arView: ARView?

    init() {
        super.init(nibName: nil, bundle: nil)
        arView = ARView(frame: .zero)
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    deinit {
        doEverythingThatsNeeded()
    }

    public func doEverythingThatsNeeded() {
        self.arView?.session.pause()
        self.arView?.session.delegate = nil
        self.arView?.removeFromSuperview()
        // Quite a few more removals and resets here, ie. for Combines AnyCancellables
        self.arView = nil
    }

}

我也从外部调用doEverythingThatsNeeded():

aRViewMemoryTest?.doEverythingThatsNeeded()
aRViewMemoryTest?.arView = nil
aRViewMemoryTest = nil

这个问题似乎与我在SwiftUI UIViewRepresentable/UIViewControllerRepresentable中 Package 了我的ARView或UIViewController的事实无关。
我相信这一定是个bug,几个月前我已经提交了一份报告。不过,我希望在苹果修复潜在问题之前能有一些变通办法。
多谢了!

ruarlubt

ruarlubt1#

UIKit版本

以下是UIKit中的解除分配过程:

import UIKit
import RealityKit

class ViewController: UIViewController {
    
    var arView: ARView? = ARView(frame: .zero)

    deinit { removingView() }
    
    func addingView() {
        self.arView?.frame = .init(x: 0, y: 0, width: 300, height: 700)
        self.view.addSubview(arView!)
    }
    
    func removingView() {
        self.arView?.session.pause()            // there's no session on macOS
        self.arView?.session.delegate = nil     // there's no session on macOS
        self.arView?.scene.anchors.removeAll()
        self.arView?.removeFromSuperview()
        self.arView?.window?.resignKey()
        self.arView = nil
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()            
        addingView()
        
        let boxAnchor = try! Experience.loadBox()
        arView?.scene.anchors.append(boxAnchor)
        
        removingView()
    }
}

然而,真实的的问题是,当ARView被取消初始化时,分配给它的内存并没有完全被取消分配(即使代码是100%正确的)。但也有一个好消息--当你再次使用这个ARView时,分配给它的内存将被使用。
如果您需要更多信息,请阅读此帖子了解详情。

SwiftUI版本

由于SwiftUI Viewsvalues,因此没有针对它们的释放过程(因为它在UIKit中)。但是,如果我们删除ARView,仍然会发生内存泄漏。

import SwiftUI
import RealityKit

struct ARViewContainer: UIViewRepresentable {

    func makeUIView(context: Context) -> ARView {        
        let arView = ARView(frame: .zero)
        let boxAnchor = try! Experience.loadBox()
        arView.scene.anchors.append(boxAnchor)
        return arView
    }

    func updateUIView(_ uiView: ARView, context: Context) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 3.0) {
            uiView.removeFromSuperview()
        }
    }
}

删除ARView最方便的方法当然是使用按钮。

import SwiftUI
import RealityKit

struct ContentView : View {
    
    @State private var isPressed: Bool = false

    var body: some View {
        ZStack {
            ARViewContainer(isPressed: $isPressed).ignoresSafeArea()
            VStack {
                Spacer()
                Button("Remove ARView") { isPressed = true }
            }
        }
    }
}   
struct ARViewContainer: UIViewRepresentable {
    
    @Binding var isPressed: Bool
    
    func makeUIView(context: Context) -> ARView {
        let arView = ARView(frame: .zero)
        let boxAnchor = try! Experience.loadBox()
        arView.scene.anchors.append(boxAnchor)
        return arView
    }     
    func updateUIView(_ uiView: ARView, context: Context) {
        if isPressed {
            uiView.removeFromSuperview()
        }
    }
}

相关问题