I created 2 different schemas, and made a small change to one of them. I added a property to the model called "version". To see if the migration went through, I setup the migration plan to set version to "1.1.0" in willMigrate. In the didMigrate, I looped through the new version of Tags to check if version was set, and if not, set it. I did this incase the willMigrate didn't do what it was supposed to. The app built and ran successfully, but version was not set in the Tag I created in the app.
Here's the migration:
enum MigrationPlanV2: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[DataSchemaV1.self, DataSchemaV2.self]
}
static let stage1 = MigrationStage.custom(
fromVersion: DataSchemaV1.self,
toVersion: DataSchemaV2.self,
willMigrate: { context in
let oldTags = try? context.fetch(FetchDescriptor<DataSchemaV1.Tag>())
for old in oldTags ?? [] {
let new = Tag(name: old.name, version: "Version 1.1.0")
context.delete(old)
context.insert(new)
}
try? context.save()
},
didMigrate: { context in
let newTags = try? context.fetch(FetchDescriptor<DataSchemaV2.Tag>())
for tag in newTags ?? []{
if tag.version == nil {
tag.version = "1.1.0"
}
}
}
)
static var stages: [MigrationStage] {
[stage1]
}
}
Here's the model container:
var sharedModelContainer: ModelContainer = {
let schema = Schema(versionedSchema: DataSchemaV2.self)
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(
for: schema,
migrationPlan: MigrationPlanV2.self,
configurations: [modelConfiguration])
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
I ran a similar test prior to this, and got the same result. It's like the code in my willMigrate isn't running. I also had print statements in there that I never saw printed to the console. I tried to check the CloudKit console for any information, but I'm having issues with that as well (separate post).
Anyways, how can I confirm that my migration was successful here?
Selecting any option will automatically load the page
Post
Replies
Boosts
Views
Activity
I previously got this error when I used a PassKey to log in. I'm not using that. I've put my password in multiple times, closed the browser, etc. It doesn't seem to be working. The only thing I can think is that because my Mac is using a different iCloud account, it's not letting me.
Does anyone have any ideas?
I have a Split View with the sidebar, content, and detail. Everything is working, but when I select on a NavigationLink in my detail view, the back button is seen next to the title above the content view. I want that back button to be displayed in the top bar on the left side of the detail view. I was expecting it to do this automatically, but I must be missing something.
This is where I want it to appear.
This is where it appears.
I made a simplified version of my code, because it would be too much to post but this has the same behavior.
struct TestView: View {
enum SidebarSelections {
case cycles
}
@State private var sidebarSelection: SidebarSelections = .cycles
var body: some View {
NavigationSplitView(sidebar: {
List(selection: $sidebarSelection, content: {
Label("Cycles", systemImage: "calendar")
.tag(SidebarSelections.cycles)
})
}, content: {
switch sidebarSelection {
case .cycles:
NavigationStack {
List {
// Displayed in Content
NavigationLink("Cycle link", destination: {
// Displayed in the Detail
NavigationStack {
List {
NavigationLink("Detail Link", destination: {
Text("More details")
})
}
}
})
}
}
}
}, detail: {
ContentUnavailableView("Nothing to see here", systemImage: "cloud")
})
}
}
Is what I want to do possible? Here is a Stack Overflow post that had it working at one point.
I've been trying to setup a successful migration, but it keeps failing with this error:
NSCloudKitMirroringDelegate are not reusable and should have a lifecycle tied to a given instance of NSPersistentStore.
I can't find any information about this online. I added breakpoints throughout the code in willMigrate, and it originally failed on this line:
try? context.save()
I removed that, and it still failed. After I reload the app, it doesn't run the migration again and the app loads successfully. I figured since it crashed, it would keep trying, but I guess not. Here's how my migration is setup.
enum MigrationV1ToV2: SchemaMigrationPlan {
static var schemas: [any VersionedSchema.Type] {
[SchemaV1.self, SchemaV2.self]
}
static var stages: [MigrationStage] {
[stage]
}
static let stage = MigrationStage.custom(
fromVersion: SchemaV1.self,
toVersion: SchemaV2.self,
willMigrate: { context in
// Get cycles
let cycles = try? context.fetch(FetchDescriptor<SchemaV1.Cycle>())
if let cycles {
for cycle in cycles {
// Create new recurring objects based on what's in the cycle
for income in cycle.income {
let recurring = SchemaV2.Recurring(name: income.name, frequency: income.frequency, kind: .income)
recurring.addAmount(.init(date: cycle.startDate, amount: income.amount))
context.insert(recurring)
}
for expense in cycle.expenses {
let recurring = SchemaV2.Recurring(name: expense.name, frequency: expense.frequency, kind: .expense)
recurring.addAmount(.init(date: cycle.startDate, amount: expense.amount))
context.insert(recurring)
}
for savings in cycle.savings {
let recurring = SchemaV2.Recurring(name: savings.name, frequency: savings.frequency, kind: .savings)
recurring.addAmount(.init(date: cycle.startDate, amount: savings.amount))
context.insert(recurring)
}
for investment in cycle.investments {
let recurring = SchemaV2.Recurring(name: investment.name, frequency: investment.frequency, kind: .investment)
recurring.addAmount(.init(date: cycle.startDate, amount: investment.amount))
context.insert(recurring)
}
}
//try? context.save()
} else {
print("The cycles were not able to be fetched.")
}
},
didMigrate: { context in
// Get new recurring objects
let newRecurring = try? context.fetch(FetchDescriptor<SchemaV2.Recurring>())
if let newRecurring {
for recurring in newRecurring {
// Get all recurring with the same name and kind
let sameName = newRecurring.filter({ $0.name == recurring.name && $0.kind == recurring.kind })
// Add amount history to recurring object, and then remove matching
for match in sameName {
recurring.amountHistory.append(contentsOf: match.amountHistory)
context.delete(match)
}
}
//try? context.save()
} else {
print("The new recurring objects could not be fetched.")
}
}
)
}
Here's is my modelContainer in the app file. There is a fatal error occurring here that's crashing the app.
var sharedModelContainer: ModelContainer = {
let schema = Schema(versionedSchema: SchemaV2.self)
let modelConfiguration = ModelConfiguration(schema: schema, isStoredInMemoryOnly: false)
do {
return try ModelContainer(
for: schema,
migrationPlan: MigrationV1ToV2.self,
configurations: [modelConfiguration]
)
} catch {
fatalError("Could not create ModelContainer: \(error)")
}
}()
Does anyone have any suggestions for this?
EDIT:
I found this error in the console that may be relevant.
BUG IN CLIENT OF CLOUDKIT: Registering a handler for a CKScheduler activity identifier that has already been registered (com.apple.coredata.cloudkit.activity.export.8F7A1261-4324-40B4-B041-886DF36FBF0A).
CloudKit setup failed because it couldn't register a handler for the export activity. There is another instance of this persistent store actively syncing with CloudKit in this process.
And here is the fatal error
Fatal error: Could not create ModelContainer: SwiftDataError(_error: SwiftData.SwiftDataError._Error.loadIssueModelContainer, _explanation: nil)