Search code examples
swiftswiftuiobservablexcode12observedobject

When exactly SwiftUI releases ObservableObjects


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


Solution

  • 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 .