Hello,
I'm using CoreData + CloudKit and I am facing the following error 134100 "The managed object model version used to open the persistent store is incompatible with the one that was used to create the persistent store."
All my schema updates are composed of adding optional attributes to existing entities, adding non-optional attributes (with default value) to existing entities or adding new entities Basically, only things that lightweight migrations can handle.
Every time I update the schema, I add a new model version of xcdatamodel - who only has a single configuration (the "Default" one). And I also deploy the updated CloudKit schema from the dashboard.
It worked up to v3 of my xcdatamodel, but started to crash for a few users at v4 when I added 16 new attributes (in total) to 4 existing entities.
Then again at v5 when I added 2 new optional attributes to 1 existing entity.
I'm using a singleton and here is the code:
private func generateCloudKitContainer() -> NSPersistentCloudKitContainer {
let container = NSPersistentCloudKitContainer(name: "MyAppModel")
let fileLocation = URL(...)
let description = NSPersistentStoreDescription(url: fileLocation)
description.shouldMigrateStoreAutomatically = true
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
let options = NSPersistentCloudKitContainerOptions(containerIdentifier: "iCloud.com.company.MyApp")
options.databaseScope = .private
description.cloudKitContainerOptions = options
container.persistentStoreDescriptions = [description]
container.viewContext.automaticallyMergesChangesFromParent = true
container.loadPersistentStores { description, error in
container.viewContext.mergePolicy = NSMergePolicy(merge: .mergeByPropertyObjectTrumpMergePolicyType)
if let error {
// Error happens here!
}
}
return container
}
I can't reproduce it yet. I don't really understand what could lead to this error.
Post
Replies
Boosts
Views
Activity
Greetings,
Context
Let's imagine 2 possible root Views: House and Castle.
They can both present a Room view and this room view can show a Bed view.
Let's also assume, for the sake of the example, that I want to pass the "$sheet" (Identifiable enum) from either House or Castle - which are 2 different enums - all the way to Bed, so that Bed can dismiss back to rootView. So I use a Binding.
Visually, the UI flow is
House --> \
Room --> Bed
Castle --> /
In RoomView and BedView, I expected to receive either a HouseSheet or a CastleSheet. So by receiving one at init, I set to a constant nil the other. For example, if I open a RoomView (or BedView) from a HouseView, the code would be
init(parentHouseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = parentHouseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(parentCastleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = parentCastleSheet
self.from = .castle
}
Problem
My problem now is that the .constant(nil) appears to change and triggers a refresh!
By using a simple Self._printChanges() I get the following when I navigate to a BedView (from a House origin!).
RoomView: _parentCastleSheet changed. // Why? It's a binded constant and I'm not even touching RoomView at all.
BedView: @self, @identity, _parentCastleSheet changed.
BedView: @self, _parentCastleSheet changed. // Same why?
Full code
// House & Castle
enum BuildingOrigin: String {
case house
case castle
}
enum HouseSheet: String, Hashable, Identifiable {
case room
var id: String { return self.rawValue }
}
enum CastleSheet: String, Hashable, Identifiable {
case room
var id: String { return self.rawValue }
}
// I only show HouseView for this example.
struct HouseView: View {
@State private var sheet: HouseSheet?
var body: some View {
let _ = Self._printChanges()
VStack {
Button("Open Room (Sheet)") {
self.sheet = .room
}
}
.padding()
.sheet(item: $sheet) { sheet in
switch sheet {
case .room: RoomView(houseSheet: $sheet)
}
}
}
}
// Room
enum RoomViewDestination: String, Hashable {
case bed
}
struct RoomView: View {
@State private var path = NavigationPath()
@Binding var parentHouseSheet: HouseSheet?
@Binding var parentCastleSheet: CastleSheet?
let from: BuildingOrigin
init(houseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = houseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(castleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = castleSheet
self.from = .castle
}
var body: some View {
let _ = Self._printChanges()
NavigationStack(path: $path) {
List {
NavigationLink(value: RoomViewDestination.bed) {
Text("Open Bed (Navigation)")
}
}
.navigationDestination(for: RoomViewDestination.self) { destination in
switch destination {
case .bed:
switch self.from {
case .house: BedView(parentHouseSheet: $parentHouseSheet)
case .castle: BedView(parentCastleSheet: $parentCastleSheet)
}
}
}
}
}
}
// Bed
struct BedView: View {
@Binding var parentHouseSheet: HouseSheet?
@Binding var parentCastleSheet: CastleSheet?
let from: BuildingOrigin
init(parentHouseSheet: Binding<HouseSheet?>) {
self._parentHouseSheet = parentHouseSheet
self._parentCastleSheet = .constant(nil)
self.from = .house
}
init(parentCastleSheet: Binding<CastleSheet?>) {
self._parentHouseSheet = .constant(nil)
self._parentCastleSheet = parentCastleSheet
self.from = .castle
}
var body: some View {
let _ = Self._printChanges()
Text("The \(from.rawValue) has a nice bed.")
}
}