Instruction

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Heads up... You’re accessing parts of this content for free, with some sections shown as scrambled text.

Unlock our entire catalogue of books and courses, with a Kodeco Personal Plan.

Unlock now

You’ve learned two ways to implement one-way binding between views and a view model, where a view needs only read-access to a view model object. The next question is, what do you need to do to get two-way binding, where a view can update a value in the view model object? Consider these three cases.

@State in View

You declare and instantiate the view model object in the view. Then somewhere in this view, you want to modify a value in the view model object. The easiest case is to use a binding to the view model object. For example, the view model object has a collection of objects that the view displays in a List, and you want to modify a property of an object in the list:

@State var store = TheMetStore()
...
List($store.objects, id: \.objectID) { $object in
  ...
  object.isFavorite.toggle()

Passed to View

You declare and instantiate the view model object in a view or in the app struct, then pass it as a parameter to a subview. In the subview, declare the view model object as @Bindable:

// In TheMetApp
struct TheMetApp: App {
  @State var store = TheMetStore()
  var body: some Scene {
    WindowGroup {
      ContentView(store: store)
    }
  }
}

// In ContentView
struct ContentView: View {
  @Bindable var store: TheMetStore
  ...
  List($store.objects, id: \.objectID) { $object in
    ...
    object.isFavorite.toggle()

@Environment

You declare and instantiate the view model object in the app struct or in a view, then inject it into the environment of the app or the parent view’s subtree. An environment object is read-only, but you can create a @Bindable version of it in the view:

// In TheMetApp
struct TheMetApp: App {
@State var store = TheMetStore()
  var body: some Scene {
    WindowGroup {
      ContentView()
        .environment(store)
    }
  }
}

// In ContentView
@Environment(TheMetStore.self) var store
...
  VStack {
    @Bindable var twoWayStore = store
    ...
    List($twoWayStore.objects, id: \.objectID) { $object in
    ...
      NavigationLink(object.title) {
        ObjectView(object: $object)   // ObjectView modifies object.isFavorite
      }
See forum comments
Download course materials from Github
Previous: Demo 1 Next: Demo 2