Has anyone successfully used NSStagedMigrationManager?

I've been trying to build an example of NSStagedMigrationManager from some Core Data migration tests to replace a custom migration manager solution I'd constructed, without much success.

The Core Data model has seven model versions. Most support lightweight migration, but two of the migrations in the middle of the sequence used NSMappingModel.

In the first beta, just attempting to construct an NSStagedMigrationManager from the series of stages failed with an unrecognized selector. That no longer happens in b4, but I now get an error that "Duplicate version checksums across stages detected."

If I restrict myself to just the first three versions of the model (that only require lightweight migration), I can build the migration manager. But if I attempt to use it to migrate a persistent store, it fails somewhere in NSPersistentStoreCoordinator with a nilError.

The documentation is almost nonexistent for this process, and the WWDC session that introduced it isn't much more than a breezy overview. So maybe I'm holding it wrong?

(And, yes: FB12339663)

I've come back to my test a couple of times over the last two months, and I'm still seeing the same exact issue in the final released version of Xcode 15. I sure wish I knew whether this was actually a bug, or whether I'm using this (under-documented!) API incorrectly.

Because the only sample code I can find anywhere (from the WWDC presentation) uses NSPersistentContainer, I thought I'd try re-writing my tests to do the same, rather than creating the NSPersistentStoreCoordinator directly.

Unfortunately, while that initially appears to work — loadPersistentStores(_:) calls its completion handler with a nil error — it appears that it's failing silently somewhere along the way. The container's persistentStoreCoordinator.persistentStores is empty, and attempting to save changes to its viewContext throws "This NSPersistentStoreCoordinator has no persistent stores (unknown). It cannot perform a save operation."

Same here, my XCode Version is 15.0.1

After 3 months, did you find the solution?

Have you found a solution to this problem?

My schema has 2 versions, and I want to migrate with a custom stage migration. My app crashes at launch with the following error: Thread 1: "Duplicate version checksums across stages detected.".

I filed feedback #FB13647876 and request a technical support.

I attempted to create a model by directly accessing the Managed Object Model (MOM), and the code ran successfully. I also completed the migration process. The implementation is somewhat obscure, and I believe Apple's main purpose in providing this migration method for Core Data is to offer a foundational implementation for phased migrations in SwiftData.

guard let momdURL = Bundle.main.url(forResource: "Model", withExtension: "momd") else { fatalError() }
let model1URL = momdURL.appending(component: "Model.mom")
let model2URL = momdURL.appending(component: "Model 2.mom")
guard let model1 = NSManagedObjectModel(contentsOf: model1URL) else { fatalError() }
guard let model2 = NSManagedObjectModel(contentsOf: model2URL) else { fatalError() }

let v1ModelChecksum = model1.versionChecksum
let v1ModelReference = NSManagedObjectModelReference(model: model1, versionChecksum: v1ModelChecksum)

let v2ModelChecksum = model2.versionChecksum
let v2ModelReference = NSManagedObjectModelReference(model: model2, versionChecksum: v2ModelChecksum)

let customStage = NSCustomMigrationStage(
  migratingFrom: v1ModelReference,
  to: v2ModelReference
)

let migrationManager = NSStagedMigrationManager([customStage])

let description = container.persistentStoreDescriptions.first
description?.setOption(migrationManager, forKey: NSPersistentStoreStagedMigrationManagerOptionKey)

and I have update my topic about staged migration of Core Data. https://fatbobman.com/en/posts/what-s-new-in-core-data-in-wwdc23

I've been testing out some migrations using code from [@Fat Xu](https://developer.apple.com/forums/profile/Fat Xu)'s blog (thank you for that!), and I've run into the "Duplicate version checksums across stages detected" error a few times. By using only NSCustomMigrationStage and not NSLightweightMigrationStage, it seems to work.

My observations start with the following setup:

  • My Model has four versions: v1, v2, v3, v4.
  • V1ToV2 and V3ToV4 can use lightweight migrations.
  • V2ToV3 requires a custom stage

What I found was that if I created the NSStagedMigrationManager like this:

let myCustomMigrationStageV2toV3 = NSCustomMigrationStage(
    migratingFrom: v2, 
    to: v3)
myCustomMigrationStageV2toV3.willMigrateHandler = /* do custom migration stuff */

let migrationManager = NSStagedMigrationManager([
    NSLightweightMigrationStage([v1.checksum]),
    myCustomMigrationStageV2toV3,
    NSLightweightMigrationStage([v3.checksum])
])

I would get the "Duplicate version checksums" error, probably because the custom stage and the third stage both included v3. If I change the final stage to v4.checksum, the migration succeeds. I find this somewhat confusing because in two NSLightweightMigrationStages with the same initializer, the provided version checksum is the source version in one, and the destination version in the other.

A more reliable option for me was to use NSCustomMigrationStage even where NSLightweightMigrationStage would work. For example...

let migrationManager = NSStagedMigrationManager([
    NSCustomMigrationStage(migratingFrom: v1, to: v2),
    myCustomMigrationStageV2toV3,
    NSCustomMigrationStage(migratingFrom: v3 to: v4)
])

This works fine, and I get to be certain of each stage along the way having the source and destination versions that I specify. It seems a NSCustomMigrationStage with no willMigrateHandler and no didMigrateHandler is just the same as a NSLightweightMigrationStage, but with an initializer that makes more sense.

Has anyone successfully used NSStagedMigrationManager?
 
 
Q