2023 Swift
Model your schema with SwiftData
Learn how to use schema macros and migration plans with SwiftData to build more complex features for your app. We’ll show you how to fine-tune your persistence with @Attribute and @Relationship options. Learn how to exclude properties from your data model with @Transient and migrate from one version of your schema to the next with ease. To get the most out of this session, we recommend first watching "Meet SwiftData" and "Build an app with SwiftData" from WWDC23.
Watch at developer.apple.com ↗Chapters
Code shown on screen · 8 snippets
Original Trip model
import SwiftUI
import SwiftData
final class Trip {
var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
} Adding a unique attribute
final class Trip {
(.unique) var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
} Specifying original property names
final class Trip {
(.unique) var name: String
var destination: String
(originalName: "start_date") var startDate: Date
(originalName: "end_date") var endDate: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
} Cascading delete rule
final class Trip {
(.unique) var name: String
var destination: String
(originalName: "start_date") var startDate: Date
(originalName: "end_date") var endDate: Date
(.cascade)
var bucketList: [BucketListItem]? = []
(.cascade)
var livingAccommodation: LivingAccommodation?
} Transient properties
final class Trip {
(.unique) var name: String
var destination: String
(originalName: "start_date") var startDate: Date
(originalName: "end_date") var endDate: Date
(.cascade)
var bucketList: [BucketListItem]? = []
(.cascade)
var livingAccommodation: LivingAccommodation?
var tripViews: Int = 0
} Defining versioned schemas
enum SampleTripsSchemaV1: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
final class Trip {
var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
}
enum SampleTripsSchemaV2: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
final class Trip {
(.unique) var name: String
var destination: String
var start_date: Date
var end_date: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
}
enum SampleTripsSchemaV3: VersionedSchema {
static var models: [any PersistentModel.Type] {
[Trip.self, BucketListItem.self, LivingAccommodation.self]
}
final class Trip {
(.unique) var name: String
var destination: String
(originalName: "start_date") var startDate: Date
(originalName: "end_date") var endDate: Date
var bucketList: [BucketListItem]? = []
var livingAccommodation: LivingAccommodation?
}
// Define the other models in this version...
} Implementing a SchemaMigrationPlan
enum SampleTripsMigrationPlan: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[SampleTripsSchemaV1.self, SampleTripsSchemaV2.self, SampleTripsSchemaV3.self]
}
static var stages: [MigrationStage] {
[migrateV1toV2, migrateV2toV3]
}
static let migrateV1toV2 = MigrationStage.custom(
fromVersion: SampleTripsSchemaV1.self,
toVersion: SampleTripsSchemaV2.self,
willMigrate: { context in
let trips = try? context.fetch(FetchDescriptor<SampleTripsSchemaV1.Trip>())
// De-duplicate Trip instances here...
try? context.save()
}, didMigrate: nil
)
static let migrateV2toV3 = MigrationStage.lightweight(
fromVersion: SampleTripsSchemaV2.self,
toVersion: SampleTripsSchemaV3.self
)
} Configuring the migration plan
struct TripsApp: App {
let container = ModelContainer(
for: Trip.self,
migrationPlan: SampleTripsMigrationPlan.self
)
var body: some Scene {
WindowGroup {
ContentView()
}
.modelContainer(container)
}
} Resources
Related sessions
-
13 min -
19 min -
9 min -
11 min -
16 min