如何释放RealityKit ARView()?

Hel*_*imo 6 swift arkit swiftui realitykit

我无法从内存中释放我的 RealityKit ARView()

\n\n

我知道 ARKit + SceneKit \xe2\x80\x93 存在类似问题,并具有如下解决方法:/sf/answers/3774381131/ \n这确实解决了我的问题不幸的是问题。

\n\n

上述解决方案通过手动删除所有“可疑”内容来发挥作用。这正是我在更广泛的范围内所做的:

\n\n
class ViewController_ARViewMemoryTest: UIViewController {\n\n    var arView: ARView?\n\n    init() {\n        super.init(nibName: nil, bundle: nil)\n        arView = ARView(frame: .zero)\n    }\n\n    required init?(coder: NSCoder) {\n        fatalError("init(coder:) has not been implemented")\n    }\n\n    deinit {\n        doEverythingThatsNeeded()\n    }\n\n    public func doEverythingThatsNeeded() {\n        self.arView?.session.pause()\n        self.arView?.session.delegate = nil\n        self.arView?.removeFromSuperview()\n        // Quite a few more removals and resets here, ie. for Combines AnyCancellables\n        self.arView = nil\n    }\n\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

我也从外部调用 doEverythingThatsNeeded() :

\n\n
aRViewMemoryTest?.doEverythingThatsNeeded()\naRViewMemoryTest?.arView = nil\naRViewMemoryTest = nil\n
Run Code Online (Sandbox Code Playgroud)\n\n

这个问题似乎与我将 ARView 或 UIViewController 包装在 SwiftUI UIViewRepresentable/中这一事实无关UIViewControllerRepresentable

\n\n

我相信这一定是一个错误,我几个月前已经提交了报告。不过,我希望在 Apple 解决潜在问题之前找到能够有所帮助的解决方法。

\n\n

多谢!

\n

ARG*_*Geo 2

RealityKit v2.0 | 2023 年 3 月 30 日

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()
    }
}
Run Code Online (Sandbox Code Playgroud)

然而,真正的问题是,当 ARView 被取消初始化时,为其分配的内存并未完全释放(即使代码 100% 正确)。不过,也有个好消息 - 当您再次使用此 ARView 时,将使用相同的分配内存。

如果您需要更多信息,请阅读这篇文章了解详细信息。


SwiftUI 版本

由于 SwiftUI 视图是值,因此它们不需要释放过程,就像 UIKit 中一样(我指的是deinit方法)。但是,如果我们从超级视图中删除 ARView,内存泄漏仍然会发生。

在此输入图像描述

import SwiftUI
import RealityKit

struct ContentView : View {
        
    var body: some View {
        NavigationStack {
            ZStack {
                Color.black
                                
                VStack {
                    NavigationLink(destination: RealityKitView()) {
                        Text("Load AR Scene")
                            .foregroundColor(.mint)
                            .font(.title2)
                    }
                }
            }.ignoresSafeArea()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

这是 ARViewContainer 的init(isTapped: Binding<Bool>).

struct RealityKitView : View {
    
    @State private var isTapped: Bool = false
    
    var body: some View {
        ZStack {
            Color.orange.ignoresSafeArea()
            Text("ARView was removed")
                .font(.title3)
            
            ARViewContainer(isTapped: $isTapped)
                .ignoresSafeArea()
            VStack {
                Spacer()
                Button("Remove ARView") {
                    isTapped = true
                }
                .disabled(isTapped ? true : false)
            }
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

让我们实现取消视图与其父视图的链接的方法。

struct ARViewContainer : UIViewRepresentable {
    
    let arView = ARView(frame: .zero)
    @Binding var isTapped: Bool
    
    func makeUIView(context: Context) -> ARView {
        let model = ModelEntity(mesh: .generateSphere(radius: 0.25))
        let anchor = AnchorEntity()
        model.setParent(anchor)
        arView.scene.anchors.append(anchor)
        return arView
    }
    func updateUIView(_ view: ARView, context: Context) {
        if isTapped {
            view.removeFromSuperview()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

聚苯乙烯

唉,苹果工程师还没有解决ARView的内存泄漏问题……