Meet SwiftData

Description: SwiftData is a powerful and expressive persistence framework built for Swift. We’ll show you how you can model your data directly from Swift code, use SwiftData to work with your models, and integrate with SwiftUI.

Chapters

0:00 - Intro
1:07 - Using the model macro
3:17 - Working with your data
7:02 - Use SwiftData with SwiftUI
8:10 - Wrap-up

SwiftData Logo

Intro

  • Using the model macro
  • Working with your data
  • Use SwiftData with SwiftUl

SwiftData is a powerful framework for data modeling and management. It uses Swift's new macro system to create a seamless API experience. It is naturally integrated with SwiftUI and works with other platform features, like CloudKit and Widgets.

Using the model macro

@Model

  • Powerful new Swift macro
  • Define your schema with code
  • Add SwiftData functionality to model types

@Model is a Swift macro that helps to define the model's schema from the Swift code. SwiftData schemas are normal Swift code, but when needed, can be used to annotate properties with additional metadata. Using this schema, SwiftData adds powerful functionality to the model objects.

Add import SwiftData and @Model to the model class and the schema is generated.

// Adding @Model to Trip

import SwiftData

@Model
class Trip {
var name: String 
var destination: String 
var endDate: Date 
var startDate: Date

var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}

Models in SwiftData are the source of truth and will transform the class' stored properties into persisted properties.

Attributes

SwiftData natively adapts value type properties to be used as attributes. These properties include basic value types, like string, int, and float. They can also include more complex value types, such as structs, enums, and codable types too, including collections.

Relationships

Relationships are inferred from reference types

- Other model types
- Collections of model types

SwiftData models reference types as relationships.

Additional Metadata

@Model will modify all the stored properties on a custom type using metadata like:

  • @Attribute(.unique) for uniqueness constraint
  • @Relationship for choice of inverses and delete propagation rules
  • @Transient to exclude property from model

@Relationship can be used to control the choice of inverses and specify delete propagation rules. These change the behaviors of links between models. Use the Transient macro to tell SwiftData not to include specific properties. Here is an example.

// Providing additional metadata

import SwiftData

@Model
class Trip {
    @Attribute(.unique) var name: String 
    var destination: String 
    var endDate: Date 
    var startDate: Date
    
    @Relationship(.cascade) var bucketList: [BucketListItem]? = []
    var livingAccommodation: LivingAccommodation?
}

To learn more about SwiftData modeling, check out the session:
Model your schema with SwiftData - WWDC23

# Working with your data

Model container

The Model container provides the persistent backend

- Customized with configurations. Use the default settings just by specifying the schema.
- Provides schema migration options
- Create a container by specifying the list of model types to store - optionally provide ModelConfiguration with an url, CloudKit and group container identifiers, and migration options

let container = try ModelContainer(for: [Trip.self, LivingAccommodation.self], configurations: ModelConfiguration(url: URL("path")))
  • Or in SwiftUI with the modifier
.modelContainer(for: [Trip.self, LivingAccommodation.self])`

ModelContext

With the container set up, fetch and save data with model contexts. Also can be used with a SwiftUI's view and scene modifiers to set up a container and have it in the view's environment.

import SwiftData 
import SwiftUI

@main
struct TripsApp: App {
    
    var body: some Scene {
        WindowGroup {
            ContentView()
        } 
        .modelContainer(for:
            [Trip.self, 
            LivingAccommodation.self])
        )
    }
}

Model contexts observe all the changes to the models and provide many of the actions to operate on them.

  • Tracking updates
  • Fetching models
  • Saving changes
  • Undoing changes

In SwiftUI, generally the modelContext is from the view's environment.

import SwiftData 
import SwiftUI

struct ContextView : View {
    @Environment(\.modelContext) private var context
}

// or outside the view hierarchy, a shared main actor bound context,
let context = container.mainContext

// or instantiate new contexts for a given model container.
let context = ModelContext(container)

Fetching Data

New in iOS 17, predicate works with native Swift types and uses Swift macros for strongly typed construction. It's a modern replacement for NSPredicate.

New Swift native types:
- Predicate
- FetchDescriptor
Improvements to SortDescriptor

## Predicate

  • Fully type checked.
  • #Predicate construction instead of text parsing
  • Autocompleted keypaths.

Here are a few examples of building predicates.

// I can specify all the trips whose destination is New York.
let tripPredicate = #Predicate<Trip> {
    $0.destination == "New York"
}

// I can narrow our query down to just trips about birthdays
let tripPredicate = #Predicate<Trip> {
    $0.destination == "New York" && $0.name.contains("birthday")
}

// and I can specify we're only interested in trips planned for the future, as opposed to any of our past adventures. 

let today = Date()
let tripPredicate = #Predicate<Trip> { 
    $0.destination == "New York" &&
    $0.name.contains("birthday") &&
    $0.startDate > today
}

We can use the new FetchDescriptor type and instruct our ModelContext to fetch those trips.

let descriptor = FetchDescriptor<Trip>(predicate: tripPredicate)

let trips = try context.fetch (descriptor)

SortDescriptor

  • Updated to support all Comparable types
  • Swift native keypaths..

Swift SortDescriptor works together with FetchDescriptor and is getting some updates to support native Swift types and keypaths

let descriptor = FetchDescriptor<Trip>(
    sortBy: SortDescriptor(\Trip.name),
    predicate: tripPredicate
)
let trips = try context.fetch(descriptor)

More FetchDescriptor options

  • relationships to prefetch
  • result limits
  • exclude unsaved changes and more

Modifying Data

Basic operations

  • Inserting
  • Deleting
  • Saving
  • Changing

Delete persistent objects marking them for deletion, and committing them to the persistent container.

var myTrip = Trip(name: "Birthday Trip", destination: "New York")

// Insert a new trip
context.insert(myTrip)

// Delete an existing trip
context.delete(myTrip)

// Manually save changes to the context
try context.save()
  • The @Model macro modifies stored properties for change tracking and observation
  • Updated automatically by the ModelContext

To learn more about SwiftData containers and contexts and driving its operations, check out the session:
Dive deeper into SwiftData - WWDC23

# Use SwiftData in SwiftUI

  • Seamless integration with SwiftUI
  • Easy configuration
  • Automatically fetch data and update views

View modifiers

  • Configure data store with .modelContainer which is propagated throughout SwiftUI environment
  • Fetching in SwiftUI with @Query
  • No need for @Published and SwiftUI automatically updates
// @Query

import SwiftData
import SwiftUI

struct ContentView: View  {
    @Query(sort: \.startDate, order: .reverse) var trips: [Trip]
    @Environment(\.modelContext) var modelContext
    
    var body: some View {
       NavigationStack() {
          List {
             ForEach(trips) { trip in 
                 // ...
             }
          }
       }
    }
}

Observing changes

  • No need for @Published
  • SwiftUl automatically refreshes

SwiftData supports the all-new observable feature for your modeled properties. SwiftUI will automatically refresh changes on any of the observed properties. SwiftUI and SwiftData work hand in hand

Learn more about using these frameworks together in our session:
Build an app with SwiftData - WWDC23

SwiftData Logo

Resources

Adopting SwiftData for a Core Data app
Have a question? Ask with tag wwdc2023-10187
Search the forums for tag wwdc2023-10187
SwiftData

# Related Videos

Build an app with SwiftData - WWDC23
Discover Observation in SwiftUI - WWDC23
Dive deeper into SwiftData - WWDC23
Migrate to SwiftData - WWDC23
Model your schema with SwiftData - WWDC23
What’s new in Swift - WWDC23
What’s new in SwiftUI - WWDC23

Missing anything? Corrections? Contributions are welcome 😃

Related

Written by

laurent b

laurent b

👨🏻‍💻 | Passionate for Swift(UI), 🐍, | coffee ☕️ & cycling 🚴🏻‍♂️ | He/Him