Hi,
I'm struggling with SwiftData and the components for migration and could really use some guidance. My specific questions are
- Is it possible to go from an unversioned schema to a versioned schema?
- Do all @Model classes need to be converted?
- Is there one VersionedSchema for the entire app that handles all models or one VersionedSchema per model?
- What is the relationship, if any, between the models given to ModelContainer in a [Schema] and the models in the VersionedSchema in a [any PersistentModel.Type]
I have an app in the AppStore. I use SwiftData and have four @Models defined. I was not aware of VersionedSchema when I started, so they are unversioned. I want to update the model and am trying to convert to a VersionedSchema. I've tried various things and can't even get into the migration plan yet. All posts and tutorials that I've come across only deal with one Model, and create a VersionedSchema for that model.
I've tried to switch the one Model I want to update, as well as switching them all. Of course I get different errors depending on what configuration I try.
It seems like I should have one VersionedSchema for the app since there is the static var models: [any PersistentModel.Type]
property. Yet the tutorials I've seen create a TypeNameSchemaV1
to go with the @Model TypeName.
Which is correct? An AppNameSchemaV1
which defines four models, or four TypeNameSchemaV1
?
Any help will be much appreciated
First, I'd like to point you to the following post, where I provided an example that demonstrates how to wrap SwiftData models with a versioned schema (VersionedSchema
).
Based on that example, we can look into your questions:
Is it possible to go from an unversioned schema to a versioned schema?
Yes. Assuming you have a model named Item
at the beginning (version 1):
@Model
final class Item {
var timestamp: Date = Date.now
init(timestamp: Date = .now) {
self.timestamp = timestamp
}
}
To evolve to version 2, you wrap Item
with a versioned schema in your version 2 app:
enum ItemSchemaV1: VersionedSchema {
static var versionIdentifier: Schema.Version {
return Schema.Version(1, 0, 0) //"ItemSchemaV1"
}
static var models: [any PersistentModel.Type] {
[Item.self]
}
@Model
final class Item {
var timestamp: Date = Date.now
init(timestamp: Date = .now) {
self.timestamp = timestamp
}
}
}
From there, you can create your version 2 schema and migration plan (SchemaMigrationPlan
), as shown in the mentioned example. When SwiftData runs the migration plan, it maps Items
in the version 1 store, to ItemSchemaV1.Items
(because their version hashes are the same, I believe), and migrates the store to version 2.
Do all @Model classes need to be converted?
I am not quite clear what the real question here – If you are asking whether you need to put all the models in a versioned schema, the answer is yes.
Is there one VersionedSchema for the entire app that handles all models or one VersionedSchema per model?
It should be one versioned schema for each version. In the mentioned example, Item
is wrapped in ItemSchemaV1
, and both Item2
and the new version Item
are wrapped in ItemSchemaV2
.
What is the relationship, if any, between the models given to ModelContainer in a [Schema] and the models in the VersionedSchema in a [any PersistentModel.Type]
The schema used to create a model container should be the current version schema, in this case, version 2 schema.
Best,
——
Ziqiao Chen
Worldwide Developer Relations.