Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binding value from an ObservableObject

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) 
like image 331
user1046037 Avatar asked Dec 10 '19 03:12

user1046037


People also ask

What is a binding value?

A key function of morality is to regulate social behavior. Research suggests moral values may be divided into two types: binding values, which govern behavior in groups, and individualizing values, which promote personal rights and freedoms.

What does binding mean in Swift?

A binding in SwiftUI is a connection between a value and a view that displays and changes it. You can create your own bindings with the @Binding property wrapper, and pass bindings into views that require them.

What is binding in Xcode?

A binding connects a property to a source of truth stored elsewhere, instead of storing data directly. For example, a button that toggles between play and pause can create a binding to a property of its parent view using the Binding property wrapper.

What is EnvironmentObject?

What is an @EnvironmentObject? An @EnvironmentObject is an object living in the current environment, available to read whenever needed. An environment object is defined at a higher-level view, and can any child view can access it if needed.


2 Answers

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.
like image 58
Asperi Avatar answered Oct 04 '22 20:10

Asperi


  1. You have several options to observe the ObservableObject. If you want to be in sync with the state of the object, it's inevitable to observe the state of the stateful object. From the options, the most commons are:

    • @State
    • @ObservedObject
    • @EnvironmentObject

It is upto you, which one suits your use case.

  1. No. But you need to have an object which can be observed of any change made to that object in any point in time.

In reality, you will have something like this:

class Car: ObservableObject {     @Published var isReadyForSale = true }  struct ContentView: View {      // It's upto you whether you want to have other type      // such as @State or @ObservedObject     @EnvironmentObject var car: Car      var body: some View {         SaleButton(isOn: $car.isReadyForSale)     }  }  struct SaleButton: View {     @Binding var isOn: Bool     var body: some View {         Button(action: {             self.isOn.toggle()         }) {             Text(isOn ? "Off" : "On")         }     } } 

If you are ready for the @EnvironmentObject you will initialize your view with:

let contentView = ContentView().environmentObject(Car()) 
like image 32
nayem Avatar answered Oct 04 '22 22:10

nayem