Search code examples
swiftuixcode15ios17observation

@State object is being created and destroyed needlessly


A SwiftUI View that holds on to a model using @State is having its model created and destroyed even when the View is not changing.

This is under the new Observation macro, running in Xcode 15.0, with a min deployment of iOS 17.

import SwiftUI
import Observation

struct ContentView: View {
    @State var showView = false

    var body: some View {
        VStack {
            PersonView()

            Button("show view") {
                showView.toggle()
            }
            
            if showView {
                Text("new view")
            }
        }
    }
}

@Observable
class Person {
    var name: String

    init(name: String) {
        self.name = name
        print("model create \(self.name)")
    }
        
    deinit {
        print("model deinit \(self.name)")
    }
}

struct PersonView: View {
    @State private var model = Person(name: "swift")
    
    var body: some View {
        Text(model.name)
    }
}

Expected: Tapping the button continuously I expected to see only this in the console.

model create swift

Actual: Tapping the button continuously produces this output in the console.

model create swift
model create swift
model create swift
model deinit swift
model create swift
model deinit swift
model create swift
model deinit swift
...

Solution

  • It's true, using @State with Observable causes a memory leak. It seems we'll have to wait until iOS 18 for another property wrapper that supports Observable since Apple were unable to address this in the beta cycle. In the meantime your object will need to be a singleton and just stick to structs for your model types. Eg make a PersonStore singleton observable object and have an array of Person structs.