SwiftUI - memory leak in NavigationView

前端 未结 3 586
时光取名叫无心
时光取名叫无心 2021-01-05 07:35

I am trying to add a close button to the modally presented View\'s navigation bar. However, after dismiss, my view models deinit method is never called. I\'

3条回答
  •  梦毁少年i
    2021-01-05 08:07

    I recommend design-level solution, ie. decomposing navigation bar item into separate view component breaks that undesired cycle referencing that result in leak.

    Tested with Xcode 11.4 / iOS 13.4 - ViewModel destroyed as expected.

    Here is complete test module code:

    struct CloseBarItem: View { // separated bar item with passed binding
        @Binding var presentation: PresentationMode
        var body: some View {
            Button(action: {
                self.presentation.dismiss()
            }) {
                Text("close")
            }
        }
    }
    
    struct ModalView: View {
        @Environment(\.presentationMode) private var presentation
        @ObservedObject var viewModel: ViewModel
    
        var body: some View {
    
            NavigationView {
                Text("Modal is presented")
                .navigationBarItems(leading: 
                    CloseBarItem(presentation: presentation)) // << decompose
            }
        }
    }
    
    class ViewModel: ObservableObject {    // << tested view model
        init() {
            print(">> inited")
        }
    
        deinit {
            print("[x] destroyed")
        }
    }
    
    struct TestNavigationMemoryLeak: View {
        @State private var showModal = false
        var body: some View {
            Button("Show") { self.showModal.toggle() }
                .sheet(isPresented: $showModal) { ModalView(viewModel: ViewModel()) }
        }
    }
    
    struct TestNavigationMemoryLeak_Previews: PreviewProvider {
        static var previews: some View {
            TestNavigationMemoryLeak()
        }
    }
    

提交回复
热议问题