-
What’s new in SwiftData
Discover the latest enhancements to SwiftData. We'll show you how to persist custom and third-party types using Codable, and group fetched data into sections in your SwiftUI app. We'll also explore how to observe data store changes anywhere else using ModelResultsObserver and HistoryObserver, giving you the flexibility to drive powerful state objects, integrate with delegate-based architectures, and react precisely to model updates.
Chapters
- 0:00 - Introduction
- 0:53 - Sectioning your fetches
- 2:56 - Using custom types
- 6:26 - Observing data stores with ResultsObserver
- 9:41 - Observing history with HistoryObserver
- 12:20 - Next steps
Resources
Related Videos
WWDC26
WWDC24
-
Search this video…
-
-
0:01 - Sectioned fetching
// Sectioned fetching struct TripListView: View { @Query(sort: \Trip.startDate, sectionBy: \.destination) var trips: [Trip] var body: some View: { List(selection: $selection) { ForEach(_trips.sections) {section in Section(section.id) { ForEach(trips) {trip in TripListItem(trip: trip) } } } } } } -
4:59 - Using Codable
// Using Codable import SwiftData @Model class Trip { struct Location: Codable { var latitude: Double var longitude: Double } var name: String var destination: String var startDate: Date var endDate: Date var location: Location? @Attribute(.codable) var mapItemIdentifier: MKMapItem.Identifier? } -
8:20 - // Use observation to update map bounds
// Use observation to update map bounds @Observable @MainActor final class MapCameraController { private let modelResultsObserver: ModelResultsObserver<Trip> var bounds: MapCameraBounds? private var token: ObservationTracking.Token? init(modelContext: ModelContext) throws { modelResultsObserver = try ModelResultsObserver<Trip>(modelContext: modelContext) token = withContinuousObservation(options: [.didSet]) {[weak self], event in self?.bounds = self?.calculateBounds(trips: modelResultsObserver.results) } } private func calculateBounds(trips: [Trip]) -> MapCameraBounds? { / * */ } } -
8:21 - // Using HistoryObserver to sync with a server
// Using HistoryObserver to sync with a server @SyncActor final class ServerSync { private let observer: HistoryObserver private var token: ObservationTracking.Token? func start() throws { self.observer = try HistoryObserver(authors: ["App"], modelContainer: modelContainer) token = withContinuousObservation(options: .didSet) {[weak self] _ in _ = self?.observer.eventCounter self?.processChanges() } } private func processChanges() { // Fetch and process history transactions } }
-
-
- 0:00 - Introduction
What's new in SwiftData for Apple's 2027 releases, with a preview of the agenda: sectioning fetches, using custom types, and observing data stores.
- 0:53 - Sectioning your fetches
Use @Query's new sectionBy: parameter to group results by a key path. Access the underlying query via the underscore-prefixed name to iterate sections, each with an id and a collection of models — demonstrated by grouping trips by destination in SampleTrips.
- 2:56 - Using custom types
Store types SwiftData can't model natively — like MKMapItem.Identifier — by marking properties with @Attribute(.codable). Treat codable as an escape hatch for external types, not types you own; modeling your own types as @Model or supported value types unlocks filtering, sorting, and migration.
- 6:26 - Observing data stores with ResultsObserver
The new ResultsObserver brings Query-style fetching to non-SwiftUI code. Combine it with withContinuousObservation(didSet:) to react to model changes anywhere in your app — shown updating map camera bounds as trips change.
- 9:41 - Observing history with HistoryObserver
HistoryObserver exposes a single observable eventCounter that ticks when new persistent-history transactions arrive. Pair it with ModelContext.fetchHistory() to filter by model type or transaction author — ideal for syncing changes to an external server.
- 12:20 - Next steps
Recap: section your fetches, adopt codable types, react to data changes with ResultsObserver, and observe history with HistoryObserver.