Skip to content
Prepare to Grow

SwiftUI Fundamentals

State and Bindings

Model local source-of-truth state, pass writable projections with Binding, and preserve predictable one-way data flow.

Intermediate5 min read2 guided activities

Before you begin

What you will understand

  • Identify the source of truth for a value.
  • Use State for local view-owned state.
  • Pass Binding when a child needs to edit parent-owned state.
  • Avoid duplicated and derived state.
01

Learning stage

Concept Explanation

A SwiftUI interface changes when its data changes. State marks local, private source-of-truth data that SwiftUI stores for a view's stable identity. The property wrapper connects mutations to view invalidation; the View struct itself remains a lightweight value.

Binding is not a second copy of a value. It is a readable and writable projection into state owned elsewhere. A parent can pass $property to a child that needs to edit that value while ownership remains clear. If a child only displays the value, pass the value itself instead.

Store the minimum source of truth. Calculate derived values such as isFormValid from their inputs rather than synchronizing another state property. Lift state to the nearest common owner when multiple children must coordinate, but avoid moving purely local interaction state into a global model.

  • @State: persistent storage owned by a view identity.
  • Binding<Value>: read-write access to state owned elsewhere.
  • $value: the projected binding from a property wrapper.
  • Derived value: computed from source state rather than stored separately.
  • One-way flow: values move down; user actions move up.
02

Learning stage

Syntax & Examples

The parent owns the draft name, while the focused editor receives a binding and reports save intent separately.

ProfileEditor.swiftswift
import SwiftUI

struct ProfileScreen: View {
  @State private var draftName = "Mina"
  @State private var savedMessage: String?

  var body: some View {
    Form {
      NameEditor(name: $draftName)

      Button("Save") {
        savedMessage = "Saved (draftName.trimmingCharacters(in: .whitespaces))"
      }
      .disabled(draftName.trimmingCharacters(in: .whitespaces).isEmpty)

      if let savedMessage { Text(savedMessage).foregroundStyle(.secondary) }
    }
  }
}

struct NameEditor: View {
  @Binding var name: String

  var body: some View {
    TextField("Display name", text: $name)
  }
}
The form-valid condition is derived instead of stored, and the child edits the parent's single source of truth through Binding.
03

Learning stage

Real-World Usage

Connect the SwiftUI concept to complete, maintainable application features.

  • Control a toggle, text field, selection, disclosure, or sheet from local state.
  • Let an editor modify a parent-owned draft through bindings.
  • Coordinate sibling views by lifting their shared state to a parent.
  • Represent UI state with an enum when loading, content, empty, and failure are mutually exclusive.
04

Learning stage

Common Mistakes

Identify patterns that weaken ownership, identity, adaptation, accessibility, or user experience.

  • Initializing State repeatedly from changing parent input and expecting it to stay synchronized.
  • Passing a binding to a child that only needs to read.
  • Storing derived values that can disagree with their source inputs.
  • Using State for durable domain data that belongs to an observable model or repository.
  • Creating several Boolean properties for states that cannot validly coexist.
05

Learning stage

Practice Exercises

Build the behavior in a small Xcode project and review it in multiple states.

Activity 1

Build a bound stepper

Create a parent that owns a study-minute goal and a child editor that receives a Binding<Int>. Derive a progress label from the value.

Hint: The child should not create another State copy of the goal.

Activity 2

Replace Boolean state

Replace isLoading, hasError, and isEmpty flags with one enum and render each valid screen state with switch.

Hint: Include associated data for content and failure messages.

06

Learning stage

Knowledge Check

Answer each question before revealing the explanation.

QUESTION 1

What does Binding represent?

  1. A.Read-write access to a value owned elsewhere
  2. B.A permanent global variable
  3. C.An immutable copy
  4. D.A network request
Reveal answer

Read-write access to a value owned elsewhere

A binding keeps one source of truth while allowing a child or control to edit it.

QUESTION 2

Should isFormValid usually be stored as separate State?

Reveal answer

No. It should usually be derived from the current field values.

Storing derivable state creates synchronization paths and possible contradictions.

07

Learning stage

Interview Preparation

Explain the design in terms of data flow, identity, lifecycle, platform behavior, and trade-offs.

How do you decide where SwiftUI state should live?

Short answer: Place the source of truth at the nearest stable owner that needs to coordinate every consumer and editor.

Explore the detailed answer

Keep private interaction state local. If multiple siblings need the same value, lift it to their parent. Shared feature data may belong to an observable model. Pass immutable values to readers and bindings to editors. Avoid duplicating state or storing values that can be computed.

Possible follow-ups

  • • What is the difference between State and Binding?
  • • Why can duplicated state become inconsistent?
08

Learning stage

Key Takeaways

Predictable SwiftUI begins with explicit ownership. State owns local truth, Binding edits truth owned elsewhere, and derived values remain computations rather than additional synchronized storage.

  • State is private storage tied to view identity.
  • Binding is a projection, not a copy.
  • Pass values to readers and bindings to editors.
  • Store minimal source-of-truth data.
  • Lift state only as high as coordination requires.