Our app has an architecture based on ViewModels.
Currently, we are working on migrating from the ObservableObject protocol to the Observable macro (iOS 17+). The official docs about this are available here: https://developer.apple.com/documentation/swiftui/migrating-from-the-observable-object-protocol-to-the-observable-macro
Our ViewModels that were previously annotated with @StateObject now use just @State, as recommended in the official docs.
Some of our screens (a screen is a SwiftUI view with a corresponding ViewModel) are presented modally. We expect that after dismissing a SwiftUI view that was presented modally, its corresponding ViewModel, which is owned by this view (via the @State modifier), will be deinitialized. However, it seems there is a memory leak, as the ViewModel is not deinitialized after a modal view is dismissed.
Here's a simple code where ModalView is presented modally (through the .sheet modifier), and ModalViewModel, which is a @State of ModalView, is never deinitialized.
import SwiftUI
import Observation
@Observable
final class ModalViewModel {
init() {
print("Simple ViewModel Inited")
}
deinit {
print("Simple ViewModel Deinited") // never called
}
}
struct ModalView: View {
@State var viewModel: ModalViewModel = ModalViewModel()
let closeButtonClosure: () -> Void
var body: some View {
ZStack {
Color.yellow
.ignoresSafeArea()
Button("Close") {
closeButtonClosure()
}
}
}
}
struct ContentView: View {
@State var presentSheet: Bool = false
var body: some View {
Button("Present sheet modally") {
self.presentSheet = true
}
.sheet(isPresented: $presentSheet) {
ModalView {
self.presentSheet = false
}
}
}
}
#Preview {
ContentView()
}
Is this a bug in the iOS 17 beta version or intended behavior? Is it possible to build a relationship between the View and ViewModel in a way where the ViewModel will be deinitialized after the View is dismissed?
Thank you in advance for the help.
As written on a related thread, the issue has been fixed in iOS 17.2 beta 1.