SwiftUI Data Flow

SwiftUI Data Flow (@State and @Binding)

SwiftUI relies on a concept called a "Single Source of Truth."

Because views are just structs, they are immutable by default. You cannot change their variables once they are created.

To make your UI interactive and updatable, you use property wrappers to tell SwiftUI: "Watch this piece of data, and redraw the screen if it changes."


The @State Property Wrapper

The @State property wrapper is used for simple, local data that belongs entirely to one specific view.

When a @State variable changes, SwiftUI instantly invalidates the view and re-computes its body.

Using @State:

import SwiftUI

struct CounterView: View { // @State allows us to modify this struct property @State private var count = 0 var body: some View { VStack { Text("Count: \(count)") .font(.largeTitle) Button("Increment") { count += 1 // This triggers a UI update! } } } }

It is best practice to mark @State variables as private because they should only be modified by the view that owns them.


The @Binding Property Wrapper

What if you want a child view to modify the @State owned by its parent view?

You use the @Binding property wrapper!

A @Binding doesn't hold its own data; it simply creates a two-way connection to a piece of data stored elsewhere.

Using @Binding:

struct ParentView: View {
    @State private var isOn = false
    var body: some View {
        // The $ symbol creates a Binding to the state variable
        ChildToggleView(isOn: $isOn)
    }
}

struct ChildToggleView: View { // This view expects a binding from its parent @Binding var isOn: Bool var body: some View { Toggle("Enable Feature", isOn: $isOn) } }

Notice the $ symbol used in the parent view. The dollar sign extracts the binding connection from the state variable!


Advanced Data Flow

For data that needs to be shared across many different views in your app, SwiftUI provides other tools like @Environment and the Observable macro.

We will explore those as you dive deeper into advanced app architectures.


Exercise

Which property wrapper should you use to store simple, private data that updates the local view when changed?