Question

Accessing ViewModel field in SwiftUI using Xcode 12: "Accessing State's value outside of being installed on a View"

I think this error message is new to SwiftUI in Xcode 12 since it gave 0 hits in Google while the message itself is fairly generic:

Accessing State's value outside of being installed on a View. This will result in a constant Binding of the initial value and will not update.

I have the following code (removed some fluff):

public struct ContentView: View {
    @ObservedObject var model: RootViewModel

    public var body: some View {
        VStack(alignment: .center, content: {
            Picker(selection: model.$amount, label: Text("Amount")) {
                Text("€1").tag(1)
                Text("€2").tag(2)
                Text("€5").tag(5)
                Text("€10").tag(10)
            }.pickerStyle(SegmentedPickerStyle())
            Text("Donating: €\(model.amount)").font(.largeTitle)
        }).padding(.all, 20.0)
    }
}

public class RootViewModel: ObservableObject {
    @State public var amount: Int = 1
}

I used to have the field right in the ContentView and that worked alright. Now the UI does not update anymore and I got that run-time warning instead.

 46  37672  46
1 Jan 1970

Solution

 59

Thanks to @Andrew's answer I figured out how to make it work again. First you change the @State to @Published:

@Published public var amount: Int = 1

Next, you need to change how your Picker is bound to the data:

Picker(selection: $model.amount, label: Text("Amount")) {
    Text("€1").tag(1)
    Text("€2").tag(2)
    Text("€5").tag(5)
    Text("€10").tag(10)
}.pickerStyle(SegmentedPickerStyle())

So we went from model.$amount to $model.amount.

2020-06-29

Solution

 6

Similar to the other answer, an App is different from a View. You'll get the same error message but the cause is less obvious than in the OPs example.

@main
struct MyCoolApp: App {
    @SceneStorage("testSceneStorage") private var persisted = ""

    var body: some Scene {
        WindowGroup {
            Text(persisted) // "Accessing a SceneStorage value outside of being installed on a View. This will always return the default value."
        }
    }
}

To me the word installed in this error message is confusing. I wish they'd gone with something like, "Accessing a SceneStorage / State value that is not defined on a view".

2022-04-08