When exactly SwiftUI releases ObservableObjects

1.5k Views Asked by At

I am trying to learn how SwiftUI works internally in terms of memory management. I have little doubt about it.

When I add a NavigationLink to the 2nd View which has some Search Functionality and also loading some data from the cloud.

Now when I came back to the root view, my observableObject class is still in memory.

Does anyone have any idea how SwiftUI manages the memory and release objects?

Here is a sample code of my experiment.

struct ContentView: View {
    var body: some View {
        NavigationView {
            DemoView(screenName: "Home")
                .navigationBarHidden(true)
        }
    }
}

struct DemoView:View {
    var screenName:String
    var body: some View {
        VStack{
             
            NavigationLink(destination: SecondView(viewModel:SecondViewModel())) {
                Text("Take Me To Second View")
            }
            
            Text(self.screenName)
        } 
    }
}


// Second View
class SecondViewModel:ObservableObject {
    @Published var search:String = ""
    @Published var user:[String] = []
    
    func fetchRecords() -> Void {
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 3) { [weak self] in
            self?.user = ["Hello", "There"]
        }
    }
    
}

struct SecondView:View {
    @ObservedObject var viewModel:SecondViewModel
    
    var body: some View {
        VStack {
            TextField("Search Here", text: $viewModel.search)
                .textFieldStyle(RoundedBorderTextFieldStyle())
                .padding()
            List(self.viewModel.user, id:\.self) { user in
                Text("User \(user)")
            }
        }.onAppear{
            self.viewModel.fetchRecords()
        }
    }
}

And this is what I received in-memory graph.

enter image description here

2

There are 2 best solutions below

0
On BEST ANSWER

The object lifecycle in SwiftUI is as usual. An object is deallocated by ARC when there are no more references to it. You can add deinit { print("deinit")} to your SecondViewModel and see when the object is deallocated. And yes, in your case a new SecondViewModel object will be created each time the DemoView body is evaluated, which is probably not what you want. I guggest you initialize and store the SecondViewModel object outside of the view hierarchy, and pass a reference to this global object in DemoView.body .

1
On

Ok, I probably don't remember other similar post on the same issue, but the reason of it because your SecondView, cause it is a value, still is in NavigationView when you press back, as long as until another NavigationLink is activated.

So you need either to have different independent life-cycle for SecondViewModel or, if remain as-is, to add some reset/cleanup for it, so only pure empty object left, ie

    }.onAppear{
        self.viewModel.fetchRecords()
    }.onDisappear {
        self.viewModel.cleanup()
    }