Using @AppStorage with @Observable

Written Jan 7, 2025

I wanted to persist values that I tracked in an @Observable class using @AppStorage and found pretty quickly out that it didn't work which was a bit of a disappointment.

After some googling I found a few workarounds and even a Swift package that adds another macro to patch the incompatibility.

However I found the more elegant solution in the excellent open source Ice Cubes repository. Here's a basic example based on that.

@MainActor
@Observable class Store {
    class Storage {
        @AppStorage("storage_key") var taylor = "swift"
    }

    private let storage = Storage()

    var taylor: String {
        didSet { storage.taylor = taylor }
    }

    init() {
        taylor = storage.taylor
    }
}

It can then be injected as an environment object.

struct ContentView: View {
    @State var store = Store()

    var body: some View {
        StartView()
            .environment(store)
    }
}

To store the changes, add a @Bindable to the store property.

@MainActor
struct StartView: View {
    @Environment(Store.self) var store

    var body: some View {
        @Bindable var store = store // Create a mutable binding scoped within the body

        TextField("Stored", text: $store.taylor)
    }
}

Further reading: