App Development with Swift study materials
App Development with Swift study resources

App Development with Swift: User Interfaces and App Architecture

App Development with Swift · Work through your exam, one topic at a time.

All guide sections

User Interfaces and App Architecture

Declarative UI

SwiftUI views are lightweight structs describing UI as a function of state. body must be pure and fast; never mutate state while it is being evaluated. State drives rendering: @State owns local value state, @Binding shares a value owned elsewhere, @StateObject owns a reference-type model for the view's lifetime, @ObservedObject observes a model it does not own, and @EnvironmentObject reads an injected observable object. Model classes conform to ObservableObject and publish changes with @Published. Use ForEach with stable Identifiable IDs or explicit ids to preserve identity; unstable ids reset state.

UIKit counterparts

View controllers manage a view hierarchy and follow lifecycle callbacks: viewDidLoad once, viewWillAppear and viewDidAppear, and viewDidDisappear. Outlets are weak implicitly unwrapped references to nib-owned views. Delegates are usually weak to avoid retain cycles; closures stored long-term should capture self weakly when appropriate. Update UI only on the main thread.

Architecture

MVC separates model, view, and controller; MVVM adds an observable view model that holds presentation logic and is testable without UI. Keep a single source of truth, pass dependencies explicitly, and keep networking and persistence behind protocols so they can be replaced in tests. Navigation belongs in the view layer; business rules belong in models or view models.

Traps

  • Using @StateObject for a model passed in from a parent, creating duplicate state.
  • Mutating @State inside body, causing update loops.
  • Strong delegate or closure references that leak view controllers.
  • Doing UI work off the main thread.

Rule of thumb

Ask "who owns this state?" before choosing a property wrapper. Ownership determines @StateObject versus @ObservedObject, and clarity there prevents most data-flow bugs.