@Observable/@State memory leak

Not sure if this code is supposed to leak memory or am I missing something?

import SwiftUI
import Observation

@Observable class SheetViewModel {
  let color: Color = Color.red

  init() { print("init") }
  deinit { print("deinit") }
}

struct SheetView: View {
  @State var viewModel = SheetViewModel()

  var body: some View {
    Color(viewModel.color)
  }
}

@main
struct ObservableMemoryLeakApp: App {
  @State var presented: Bool = false

  var body: some Scene {
    WindowGroup {
      Button("Show") {
        presented = true
      }
      .sheet(isPresented: $presented) {
        SheetView()
      }
    }
  }
}

Every time the sheet is presented/dismissed, a new SheetViewModel is created (init is printed) but it never released (deinit not printed). Also, all previously created SheetViewModel instances are visible in Memory Graph and have "Leaked allocation" badge.

Reverting to ObservableObject/@StateObject fixes the issue, deinit is called every time the sheet is dismissed:

-import Observation

-@Observable class SheetViewModel {
+class SheetViewModel: ObservableObject {

- @State var viewModel = SheetViewModel()
+ @StateObject var viewModel = SheetViewModel()

Does this mean there's a bug in Observation framework?

Reported as FB13015569.

Post not yet marked as solved Up vote post of okla Down vote post of okla
2.6k views

Replies

@okla I have exactly the same problem and wrote about it here: https://developer.apple.com/forums/thread/736239

Can someone from Apple engineers help with this and confirm that it is a bug that will be fixed?

We are also having this problem. Can someone from Apple engineering conform if this will be fixed?

Any news?

This issue sadly generally affects instances of reference types stored as @State, even without using the new Observation API. It can therefore be considered an iOS 17 regression since storing simple reference types as @State without @ObservableObject was possible without leaks on iOS 16 (I can also confirm that the issue does not arise with @ObservableObject conformance).

Though in general you likely want automatic observation, sometimes being able to store an instance of a non-observable reference type for the lifetime of a SwiftUI view is still useful and legitimate. This is for example how you might store an AVPlayer displaying its content in a VideoPlayer view, as show in this official code sample.

I also reported this issue as FB13126425. Sample code is available here.

  • Thanks for filing FB13126425.

Add a Comment

The issue has not been fixed in the iOS 17 RC published today. I guess there might be troubles ahead for early adopters of the new Observation API (but not only, see my previous comment) when the owning view is presented in a modal.

Seeing the same issue

Excellent news, the issue has been addressed in the iOS 17 beta 1 released yesterday. Thanks to everyone who made this important fix possible.

  • ^iOS 17 beta 1^iOS 17.2 beta 1

  • Well, that's great new I guess, except anyone running iOS 17 will still have a massively leaking app with no fix...

  • Can you please attach the link to release notes, where it's possible to read about this fix? I can't find any mention about this problem in the 17.2 beta 3 release notes.