skip to Main Content

I use SwiftData in my app and I want to update a property in my model.

This property (lets call it myData) is a Codable struct.

I have added to new properties in myData, without changing anything in my model, it crashes at app start.

If I erase the app and start from scratch, it works perfectly with my updated model.

I think there is a problem with schema migration but I don’t know how to handle it.
I use SwiftData in my app and I want to update a property in my model.

This property (lets call it myData) is a Codable struct.

I have added to new properties in myData, without changing anything in my model, it crashes at app start.

If I erase the app and start from scratch, it works perfectly with my updated model.

I think there is a problem with schema migration but I don’t know how to handle it.

Some more info, my model:

@Model
class CloudInterval: Encodable, Comparable {
    var id = UUID()
    var name: String = ""
    var order: Int = 0
    // targets
    var targetData = TargetData()
    @Relationship(deleteRule: .nullify, inverse: CloudBlock.intervals)
    var block: CloudBlock?

    init() {
    }
}

My problem is with targetData

Initially, it’s :

struct TargetData: Codable, Equatable {
    var minHeartRate: Int = 0
    var maxHeartRate: Int = 0
    var speed: Double = 0
    var time: TimeInterval = 0
    var distance: Double = 0
    var enableTargetSpeed = false
    var enableTargetHeartRate = false
    var enableTargetTime = false
    var speedTolerance: Double = 0.02
}

And I just want to add 2 new properties (1 Bool, 1 Int), and when I do that, the app crashes.
I don’t how to migrate to the new version.

2

Answers


  1. There is 2 type of migrations in SwiftData: lightweight and complex.

    While lightweight migration will execute automatically, for bigger changes you need to write your own migration plan.

    Some lightweight changess:

    • Adding one or more new model.
    • Adding one or more new properties that have a default value.
    • Renaming one or more properties.
    • Deleting properties from a model.
    • Adding or removing the .externalStorage or .allowsCloudEncryption attributes.
    • Adding the .unique attribute and all values for that property are already unique.
    • Adjusting the delete rule on relationships.

    The problem in you case is you want to update a complex type, not only add two more properties.

    You have more options to solve this:

    1. You can make the TargetData @Model as well, and create one-to-one relationships between them.

    This mean that every CloudInterval object has exactly one TargetData object attached to it.
    In this case, be careful not to try to insert both CloudInterval and TargetData objects, because inserting one automatically inserts the other.

    2. You can create complex migration using VersionedSchema

    Doing this requires four steps:

    • You need to define multiple versions of our data model.
    • You wrap each of those versions inside an enum that conforms to the VersionedSchema protocol. (It’s an enum only because we won’t actually be instantiating these directly.)
    • You create another enum that conforms to the SchemaMigrationPlan protocol, which is where you’ll handle the migrations between each
      model version.
    • You then create a custom ModelContainer configuration that knows to use the migration plan as needed.

    You can learn more about SchemaMigrationPlan from the following links:

    Login or Signup to reply.
  2. You should make migrations when you want to make changes to your data model. If your app is not published on the App Store, I recommend deleting your application and reinstalling it. However, if you want to update your app that is on the App Store, I prefer watching this video. SwiftData Migrations Tutorial

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search