Binding value from an ObservableObject

user1046037 picture user1046037 · Dec 10, 2019 · Viewed 15k times · Source

Aim:

I have a model which is an ObservableObject. It has a Bool property, I would like to use this Bool property to initialise a @Binding variable.

Questions:

  1. How to convert an @ObservableObject to a @Binding ?
  2. Is creating a @State the only way to initialise a @Binding ?

Note:

  • I do understand I can make use of @ObservedObject / @EnvironmentObject, and I see it's usefulness, but I am not sure a simple button needs to have access to the entire model.
  • Or is my understanding incorrect ?

Code:

import SwiftUI
import Combine
import SwiftUI
import PlaygroundSupport

class Car : ObservableObject {

    @Published var isReadyForSale = true
}

struct SaleButton : View {

    @Binding var isOn : Bool

    var body: some View {

        Button(action: {

            self.isOn.toggle()
        }) {
            Text(isOn ? "On" : "Off")
        }
    }
}

let car = Car()

//How to convert an ObservableObject to a Binding
//Is creating an ObservedObject or EnvironmentObject the only way to handle a Observable Object ?

let button = SaleButton(isOn: car.isReadyForSale) //Throws a compilation error and rightly so, but how to pass it as a Binding variable ?

PlaygroundPage.current.setLiveView(button)

Answer

Asperi picture Asperi · Dec 10, 2019

Binding variables can be created in the following ways:

  1. @State variable's projected value provides a Binding<Value>
  2. @ObservedObject variable's projected value provides a wrapper from which you can get the Binding<Subject> for all of it's properties
  3. Point 2 applies to @EnvironmentObject as well.
  4. You can create a Binding variable by passing closures for getter and setter as shown below:
let button = SaleButton(isOn: .init(get: { car.isReadyForSale },
                                    set: { car.isReadyForSale = $0} ))

Note:

  • As @nayem has pointed out you need @State / @ObservedObject / @EnvironmentObject / @StateObject (added in SwiftUI 2.0) in the view for SwiftUI to detect changes automatically.
  • Projected values can be accessed conveniently by using $ prefix.