销毁MainView后如何移除environmentObject并避免崩溃?
问题描述
我有如下MainView视图结构:
struct MainView: View{ @EnvironmentObject var appModel: AppDataModel @State var localAppDataModel: AppDataModel! = AppDataModel() var body: some View{ VStack { ContentView() } Button(action: { appModel.dismissAR() }, label: { Text(LocalizedString.close) .modifier(VisualEffectRoundedCorner()) }) .environmentObject(localAppDataModel) .onDisappear{ localAppDataModel.objectCaptureSession?.cancel() localAppDataModel.photogrammetrySession?.cancel() localAppDataModel.objectCaptureSession = nil localAppDataModel.photogrammetrySession = nil localAppDataModel.scanFolderManager = nil localAppDataModel.showPreviewModel = false localAppDataModel.orbit = .orbit1 localAppDataModel.orbitState = .initial localAppDataModel.isObjectFlipped = false localAppDataModel = nil } }
通过UIKit的如下方法展示该视图:
public static func present(viewC: UIViewController){ let controller = UIHostingController(rootView: MainView(appModel: .init())) mainController = controller mainController?.modalPresentationStyle = .fullScreen guard let mainController else { return } viewC.present(mainController, animated: true, completion: nil) } var mainController: UIHostingController<MainView>?
调用以下方法销毁MainView时:
public class AppDataModel: ObservableObject, Identifiable { // ... func dismissAR(){ mainController?.dismiss(animated: true) } // ... }
应用会崩溃,原因是localAppDataModel变为nil。请问如何在销毁MainView的同时,正确释放/移除localAppDataModel这个environmentObject?
解决方案
1. 移除onDisappear中直接置空localAppDataModel的代码
崩溃核心原因是:调用dismissAR()后视图进入销毁流程,onDisappear触发时,虽然你先清理了模型属性,但最后将localAppDataModel置为nil,此时可能仍有子视图(比如ContentView)在引用该模型,导致野指针访问崩溃。
修改后的onDisappear代码:
.onDisappear{ localAppDataModel.objectCaptureSession?.cancel() localAppDataModel.photogrammetrySession?.cancel() localAppDataModel.objectCaptureSession = nil localAppDataModel.photogrammetrySession = nil localAppDataModel.scanFolderManager = nil localAppDataModel.showPreviewModel = false localAppDataModel.orbit = .orbit1 localAppDataModel.orbitState = .initial localAppDataModel.isObjectFlipped = false // 删除此行:localAppDataModel = nil }
删除置空代码后,让ARC自动管理模型的内存释放即可。
2. 调整environmentObject的注入范围
当前仅给Button注入了localAppDataModel,如果ContentView也依赖该模型,需将注入范围提升至整个VStack,确保所有子视图共享同一模型实例,且生命周期与MainView绑定:
var body: some View{ VStack { ContentView() Button(action: { appModel.dismissAR() }, label: { Text(LocalizedString.close) .modifier(VisualEffectRoundedCorner()) }) } .environmentObject(localAppDataModel) // 将注入移至VStack外部 .onDisappear{ // 清理代码... } }
3. 优化dismissAR的内存管理
将mainController改为弱引用避免循环引用,并在dismiss完成后清空引用:
// 改为弱引用 weak var mainController: UIHostingController<MainView>? public static func present(viewC: UIViewController){ let controller = UIHostingController(rootView: MainView(appModel: .init())) mainController = controller controller.modalPresentationStyle = .fullScreen viewC.present(controller, animated: true, completion: nil) } // 在AppDataModel的dismissAR方法中补充完成回调 func dismissAR(){ mainController?.dismiss(animated: true) { mainController = nil // dismiss完成后清空引用 } }
4. 可选:用@StateObject替代@State管理本地模型
对于ObservableObject类型的本地状态,推荐使用@StateObject,它能更精准地管理ObservableObject的生命周期,避免不必要的重建或内存问题:
// 替换原@State定义 @StateObject var localAppDataModel = AppDataModel()
内容的提问来源于stack exchange,提问作者TheCesco1988
相关产品推荐
相关产品推荐

