在 UIKit 中将 SwiftUI 与 API 调用和导航结合使用时出现内存泄漏问题

Memory Leak Issue when Using SwiftUI in UIKit with API Calls and Navigation

提问人:Shivaditya kr 提问时间:11/16/2023 最后编辑:Brian Tompsett - 汤莱恩Shivaditya kr 更新时间:11/16/2023 访问量:40

问:

我在基于 UIKit 的 App 中的 SwiftUI 实现中遇到了内存泄漏问题。我正在使用 UIKit 视图控制器中嵌入的 SwiftUI 视图,在执行 API 调用和在视图控制器之间导航时会出现问题。

下面是代码结构的简化版本:

protocol SampleDelegate: AnyObject {
    func push()
    func pop()
}
class SampleVC: UIViewController, SampleDelegate {
    var viewModel: SampleVM!
    override func viewDidLoad() {
        super.viewDidLoad()
        let  swiftUIView = SampleView(viewModel: viewModel)
        let hostingController = UIHostingController(rootView: swiftUIView)
        self.addChild(hostingController)
        self.view.addSubview(hostingController.view)
        hostingController.didMove(toParent: self)
        hostingController.view.translatesAutoresizingMaskIntoConstraints = false
        // Set up Auto Layout constraints for the SwiftUI view
        NSLayoutConstraint.activate([
            hostingController.view.topAnchor.constraint(equalTo: view.topAnchor),
            hostingController.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
            hostingController.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
            hostingController.view.bottomAnchor.constraint(equalTo: view.bottomAnchor)
        ])
        
        // Use of viewmodel for making api controll on viewcontroller (UiKit)
        self.bindData()
    }
    func bindData() {
        viewModel.error.bind { error in
            Toast.showError(error: error ?? NetworkError.somethingWentWrong)
        }
    }
    func push() {
        // push new viewcontroller
    }
    
    func pop() {
        // pop viewcontroller
    }
}
class SampleVM: ObservableObject {
    @Published var fetchCompletion = false
    var error: Observable<Error?> = Observable(nil)
    
    func fetchData() {
        // call api to fetch and change fetched
    }
}

struct SampleView: View {
    @ObservedObject var viewModel: SampleVM
    weak var delegate: SampleDelegate?
    init(viewModel: SampleVM, delegate: SampleDelegate? = nil) {
        self.viewModel = viewModel
        self.delegate = delegate
    }
    var body: some View {
        VStack {
            Text("\((viewModel.fetchCompletion == true) ? "fetching" : "fetched")")
            Spacer()
            HStack {
                Button {
                    delegate?.pop()
                } label: {
                    Text("pop")
                }
                Button {
                    delegate?.push()
                } label: {
                    Text("push")
                }
            }
        }
    }
}

该问题似乎与内存使用有关,尤其是在推送和弹出视图控制器时。每次重复执行这些操作时,应用程序的内存占用量都会增加,这表明存在潜在的内存泄漏。

我已经确保在必要时使用 [weak self],并检查了 SwiftUI 视图层次结构中的强引用周期,但问题仍然存在。

有关如何排除和解决此内存泄漏问题的任何见解或建议将不胜感激。

已检查 SwiftUI 视图层次结构中的强引用周期。 实施了 [弱自我] 以防止闭包中的保留循环。 查看了 SwiftUI 和 UIKit 互操作性指南。 此外,我从子视图中删除了hostingview,同时弹出了同样不起作用的控制器。

SwiftUI 导航 UIKit套件

评论

1赞 lorem ipsum 11/16/2023
委托在 SwiftUI 视图中效果不佳,将委托引用放在视图模型中
0赞 Shivaditya kr 11/16/2023
工作,谢谢。:)

答:

0赞 lorem ipsum 11/16/2023 #1

委托在 SwiftUI 视图中不能很好地工作,将委托引用放在视图模型中。

SwiftUI 视图是值类型,并且存在不明显的底层存储。

SwiftUI 可以随意重新创建视图,除非属性的值位于 SwiftUI 的值中,否则它无法保持其完整性/引用。

视图模型之所以有效,是因为告诉 SwiftUI 不要分配储存空间,因为它是在其他地方维护的。@ObservedObject