Dunfey · Hotel WWDC as data, est. 1983
Front desk everything
Years
Topics

2023 SwiftUI & UI Frameworks

WWDC23 · 13 min · SwiftUI & UI Frameworks

Discover Observation in SwiftUI

Simplify your SwiftUI data models with Observation. We’ll share how the Observable macro can help you simplify models and improve your app’s performance. Get to know Observation, learn the fundamentals of the macro, and find out how to migrate from ObservableObject to Observable.

Watch at developer.apple.com ↗

Transcript all transcripts

Chapters

Code shown on screen · 8 snippets

Using @Observable swift · at 1:26 ↗
@Observable class FoodTruckModel {    
    var orders: [Order] = []
    var donuts = Donut.all
}
SwiftUI property tracking swift · at 2:12 ↗
@Observable class FoodTruckModel {    
  var orders: [Order] = []
  var donuts = Donut.all
}

struct DonutMenu: View {
  let model: FoodTruckModel
    
  var body: some View {
    List {
      Section("Donuts") {
        ForEach(model.donuts) { donut in
          Text(donut.name)
        }
        Button("Add new donut") {
          model.addDonut()
        }
      }
    }
  }
}
SwiftUI computed property tracking swift · at 3:12 ↗
@Observable class FoodTruckModel {    
  var orders: [Order] = []
  var donuts = Donut.all
  var orderCount: Int { orders.count }
}

struct DonutMenu: View {
  let model: FoodTruckModel
    
  var body: some View {
    List {
      Section("Donuts") {
        ForEach(model.donuts) { donut in
          Text(donut.name)
        }
        Button("Add new donut") {
          model.addDonut()
        }
      }
      Section("Orders") {
        LabeledContent("Count", value: "\(model.orderCount)")
      }
    }
  }
}
Using @State swift · at 4:41 ↗
struct DonutListView: View {
    var donutList: DonutList
    @State private var donutToAdd: Donut?

    var body: some View {
        List(donutList.donuts) { DonutView(donut: $0) }
        Button("Add Donut") { donutToAdd = Donut() }
            .sheet(item: $donutToAdd) {
                TextField("Name", text: $donutToAdd.name)
                Button("Save") {
                    donutList.donuts.append(donutToAdd)
                    donutToAdd = nil
                }
                Button("Cancel") { donutToAdd = nil }
            }
    }
}
Using @Environment swift · at 5:14 ↗
@Observable class Account {
  var userName: String?
}

struct FoodTruckMenuView : View {
  @Environment(Account.self) var account

  var body: some View {
    if let name = account.userName {
      HStack { Text(name); Button("Log out") { account.logOut() } }
    } else {
      Button("Login") { account.showLogin() }
    }
  }
}
Using @Bindable swift · at 6:27 ↗
@Observable class Donut {
  var name: String
}

struct DonutView: View {
  @Bindable var donut: Donut

  var body: some View {
    TextField("Name", text: $donut.name)
  }
}
Storing @Observable types in Array swift · at 7:53 ↗
@Observable class Donut {
  var name: String
}

struct DonutList: View {
  var donuts: [Donut]
  var body: some View {
    List(donuts) { donut in
      HStack {
        Text(donut.name)
        Spacer()
        Button("Randomize") {
          donut.name = randomName()
        }
      }
    }
  }
}
Manual Observation swift · at 9:18 ↗
@Observable class Donut {
  var name: String {
    get {
      access(keyPath: \.name)
      return someNonObservableLocation.name 
    }
    set {
      withMutation(keyPath: \.name) {
        someNonObservableLocation.name = newValue
      }
    }
  } 
}