SwiftUI – @State vs @Binding

38.2k Views Asked by At

I am learning iOS Programming with Swift and SwiftUI. I know very little and I am very confused about the difference between a @State and a @Binding.

If I understood it correctly, @Binding is just technically @State but it doesn't update the view. If that is the case then why would I need @Binding if I could just use @State to do the same thing?

9

There are 9 best solutions below

0
On BEST ANSWER

SwiftUI is a declarative Component-Oriented framework. You have to forget about MVC where you have controllers mediating between view and model. SwiftUI uses diffing algorithm to understand changes and update only corresponding views.

@State

  • A State property is connected to the view. A State property is permanently being read by the view. That means that every time the @State property gets changed/updated, the view gets re-rendered and eventually displays the content depending on the @State's data.
  • State is accessible only to a particular view.
  • Simple properties like strings, integers and booleans belongs to a single view - mark as private.
  • All the fields marked as State are stored in special separated memory, where only corresponded view can access and update them.

@Binding

  • BindableObject protocol, which requires a didChange property. It makes possible to use it inside Environment and rebuild view as soon as it changes.
  • The didChange property should be a Publisher, which is a part of a new Apple’s Reactive framework called Combine.
  • The main goal of Publisher is to notify all subscribers when something changes. As soon as new values appear, SwiftUI will rebuild Views.

@EnvironmentObject

  • It is a part of feature called Environment. You can populate your Environment with all needed service classes and then access them from any view inside that Environment.
  • @EnvironmentObject is accessible for every view inside the Environment.
  • @EnvironmentObject Properties created elsewhere such as shared data. App crashes if it is missing.
  • The Environment is the right way of Dependency Injection with SwiftUI.
0
On

State

  • @State keyword allows us to ask the SwiftUI to monitor the value of the property. Once the value will change, the View will be invalidated and rendered again in efficient manner.
  • A persistent value of a given type, through which a view reads and monitors the value.
  • It is just another @propertyWrapper that outlines a source of truth.
  • When you use state the framework allocate persistence storage for variable and tracks it as a dependency ... you alway has to specify an initial constant value

Binding

  • @Binding and $-prefix allows passing State property into the nested child.
  • A manager for a value that provides a way to mutate it.
  • @Binding yet another @propertyWrapper that depends explicitly on state.
  • By using the Binding property wrapper you define an explicit dependency to a source of truth without owning it, additionally you don't need to specify an initial value because binding can be derived from state.

Link for your reference: Medium

1
On

Both @State and @Binding are property wrappers.

@State

  • It is used to update the value of a variable every time.
  • We can also say it's a two way binding.
  • If we change the property state then SwiftUI will automatically reload the body of the view.
  • It is used for simple properties like strings, integers and booleans.

@Binding

  • Using this, you can access the state property of another view.
  • It will give you the read and write access for the variable.
0
On

Think of State as the single source of truth for your view, as a means of mutating a variable & invalidating the view to reflect that state.

Binding on the other hand, is a two-way connection between a view and its underlying model. A means of mutating a State that is not managed by the view (for example a Toggle that reflects and controls a bool value that the control itself has no knowledge about its storage or origin)

Finally, you can get a Binding from any State by using the $ prefix operator.

A simple guide for choosing between them would be:

  • Do I need to modify a value that is private to me? --> State
  • Do I need to modify a State of some other view? --> Binding
0
On

State simple properties like string, integers, and Booleans Belong to a single view - mark as private

Binding complex properties like custom type Sharing data in many views. Required for reference types

EnvironmentObject properties created elsewhere such as shared data App crashes if it is missing.

0
On

Here is the notes I have prepared for myself,

@State:

  • We need to use this inside a view struct
  • It’s recommended to make as private
  • We should provide default value
  • Can be used as binding
  • This is meant to store simple types like String, Int, Bool, etc...

@Binding:

  • This is used to share common data between the views
  • Best example is, presenting an sheet from View 1 and initiating dismiss action from View 2
  • No need for default value as will set it from another view

Thanks!

0
On

I want to offer a really short 'real use' explanation, which helped me clear it out. I'm not defining the State/Binding, I'm only pointing out the big difference.

@State holds value, the 'source of truth'

@Binding pass value, use as a pipeline.

One important thing regarding @State: Change will trigger a redraw. Changing the value of @State will cause the whole view to 're-execute'.

0
On

About @State and @Binding

Imagine a situation where you have two SwiftUI views. In the first view you have declared a count property, and in the second one, you have created a Tap Me button. When the button is tapped, the value of count in the first view should be updated. To implement this logic, you need a @State property wrapper in the first view and a @Binding property wrapper in the second one.

@State allows locally manipulate small amounts of data of value type. @State creates and manages values directly, so it's a Source of Truth. @Binding also refers to data of value type but owned by a different view. @Binding is not a source of truth. In order to feed the @State property to Binding<T> you need to use the $ operator (i.e. it'll look like $count). @Binding creates a two-way connection between a property and another view.

Here's the code:

enter image description here

import SwiftUI

struct FirstView: View {
    
    @State private var count: Int = 0
    
    var body: some View {
        ZStack {
            Color.black.ignoresSafeArea()
            VStack {
                SecondView(counter: $count).frame(width: 300, height: 100)
                Text("Tapped \(count) times").foregroundStyle(.white)
            }
        }
    }
}
                        
struct SecondView: View {
    
    @Binding var counter: Int
    
    var body: some View {
        ZStack {
            Color.yellow
            Text("Tap Me").onTapGesture { counter += 1 }
        }
    }
}

Besides the aforementioned property wrappers, a similar result can be achieved with the help of so-called "trinity"-kit – @StateObject, @Published and @ObservedObject.

Property Wrappers

The following pivot table represents three main characteristics (Source of Truth, purpose and semantics) of 20 commonly used SwiftUI property wrappers.


# Property Wrapper Source of Truth What it's for? Semantics
01 @AppStorage Yes reads/writes from UserDefaults value
02 @Binding no creates a two-way connection value
03 @Environment no reads data from the system value
04 @EnvironmentObject no reads a shared object from multiple views reference
05 @FetchRequest Yes use it for CoreData fetch request value
06 @FocusedBinding no observing & unwrapping state bindings from the focused view value
07 @FocusedValue no simpler version of @FocusedBinding value
08 @GestureState Yes stores values of active gesture value
09 @Namespace Yes is a wrapper for namespace.id that prevents name collision value
10 @ObservedObject no refers to instance of external class that conforms to ObservableObject reference
11 @Published Yes is attached to properties inside ObservableObject value
12 @ScaledMetric Yes allow app views to scale given user's Dynamic Type settings value
13 @SceneStorage Yes restores system state's lightweight data value
14 @State Yes manipulates view's data locally value
15 @StateObject Yes stores a new instance that conforms to ObservableObject reference
16 @NSApplicationDelegateAdaptor Yes creates an AppKit app delegate protocol
17 @UIApplicationDelegateAdaptor Yes creates an UIKit app delegate protocol
18 @Observable it's macro an iOS 17 replacement for ObservableObject + @Published + @ObservedObject pattern reference
19 @Query it's macro reads Destination objects managed by SwiftData reference
20 @Model it's macro makes a class load and store from SwiftData reference

How to...

The following are examples of how you can use four popular property wrappers.

0
On

Use 3 simple heuristics to decide when to use @State or @Binding:

  1. A single view redraws when it changes state:
  • View manages it's own @State variable
  1. A child view redraws when it's parent view changes state:

@State -> @Binding

  • Parent manages @State
  • Parent passes @State to child via constructor
  • Child keeps @Binding to passively track changes to @State
  1. One or more grandchild views redraw when changes are made up the hierarchy:

@ StateObject <-> @ EnvironmentObject

  • Top level view manages @StateObject
  • @StateObject is passed to highest ancestor view via .environmentObject()
  • All child/grandchild views store their own reference vis @EnvironmentObject

Use @StateObject and @EnvironmentObject so you can share data directly with grandchildren, these wrappers are equivalent to @State and @Binding but allow you to skip children