'SwiftUI - How to deinit a StateObject when navigating back?

I want my @StateObject to be deinitialized as soon as possible after I navigate back, but it seems that the object is held in memory. "Deint ViewModel" is not being printed on back navigation, its first printed after I navigate again to the View I was coming from. Is there a way to release the @StateObject from memory on back navigation?

struct ContentView: View {
    var body: some View {
        NavigationView {
            NavigationLink(destination: TestView(), label: { Text("Show Test View") })
        }
    }
}

struct TestView: View {
    
    @StateObject private var viewModel = ViewModel()
    
    var body: some View {
        Text("Test View")
    }
}

final class ViewModel: ObservableObject {
    deinit {
        print("Deint ViewModel")
    }
}


Solution 1:[1]

I don't have a brilliant answer on all situations that prevent the deinitialization the @StateObject, but I found that leaving background async tasks running prevents the deinitialization.

In my case, I had several cancellables registered to listen to PassthroughSubject and/or CurrentValueSubject (that I used to handle external changes on my model and exposing the result to the view), but I never cancelled them. As soon as I did it in the view using .onDisappear, it worked.

So my views all "subscribe" to the view model (I have a viewModel.subscribe() method) using .onAppear and then "unsubscribe" to the view model (I have a viewModel.subscribe() method) using .onDisappear. Doing so, the @StateObject is deinitialized when the view is dismissed.

Solution 2:[2]

I think you should use @ObservedObject private var viewModel: ViewModel instead, then inject new ViewModel instance from outside of TestView

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 GregP
Solution 2 Long Vu