Because I added widgets that need access to the CoreData store, I have moved the store into a shared AppGroup container. That has worked well, with no issues. However, I have been unable to get it to sync with iCloud. I can sync a store in the app's storage just fine.
My PersistenceController
is as follows:
struct PersistenceController {
static let shared = PersistenceController()
let context: NSManagedObjectContext
let container: NSPersistentCloudKitContainer
let coordinator: NSPersistentStoreCoordinator
init(inMemory: Bool = false) {
container = NSPersistentCloudKitContainer(name: CDConstants.containerName)
let url = AppGroup.group.containerURL.appendingPathComponent(CDConstants.containerNameSQLite)
let description = NSPersistentStoreDescription(url: url)
description.setOption(true as NSNumber, forKey: NSPersistentHistoryTrackingKey)
description.setOption(true as NSNumber, forKey: NSPersistentStoreRemoteChangeNotificationPostOptionKey)
description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: CDConstants.containerName
)
container.persistentStoreDescriptions = [description]
context = container.viewContext
context.mergePolicy = NSMergeByPropertyStoreTrumpMergePolicy
coordinator = container.persistentStoreCoordinator
// MARK: UndoManager Support
container.viewContext.undoManager = UndoManager()
if inMemory {
container.persistentStoreDescriptions.first!.url = URL(fileURLWithPath: "/dev/null")
}
container.loadPersistentStores(completionHandler: { (storeDescription, error) in
if let error = error as? NSError {
print("loadPersistentStores: error \(error), \(error.userInfo) for store \(storeDescription.description)")
}
})
// MARK: Cloudkit Merge
context.automaticallyMergesChangesFromParent = true
// MARK: Cloudkit Schema Initialization
#if DEBUG
// do {
// try container.initializeCloudKitSchema(options: [.printSchema])
// } catch {
// PersistenceController.logger.error("Schema initialization error: \(error)")
// }
#endif
}
}
I have debugging turned on for CoreData and I get this in the console:
CoreData: debug: CoreData+CloudKit: -[PFCloudKitOptionsValidator validateOptions:andStoreOptions:error:](36): Validating options: <NSCloudKitMirroringDelegateOptions: 0x600003000ab0> containerIdentifier:containerName databaseScope:Private ckAssetThresholdBytes:<null> operationMemoryThresholdBytes:<null> useEncryptedStorage:NO useDeviceToDeviceEncryption:NO automaticallyDownloadFileBackedFutures:NO automaticallyScheduleImportAndExportOperations:YES skipCloudKitSetup:NO preserveLegacyRecordMetadataBehavior:NO useDaemon:YES apsConnectionMachServiceName:<null> containerProvider:<PFCloudKitContainerProvider: 0x6000000083b0> storeMonitorProvider:<PFCloudKitStoreMonitorProvider: 0x6000000083c0> metricsClient:<PFCloudKitMetricsClient: 0x6000000083d0> metadataPurger:<PFCloudKitMetadataPurger: 0x6000000083e0> scheduler:<null> notificationListener:<null> containerOptions:<null> defaultOperationConfiguration:<null> progressProvider:<NSPersistentCloudKitContainer: 0x600001744540> test_useLegacySavePolicy:YES archivingUtilities:<PFCloudKitArchivingUtilities: 0x6000000083f0> bypassSchedulerActivityForInitialImport:NO bypassDasdRateLimiting:NO
storeOptions: {
NSInferMappingModelAutomaticallyOption = 1;
NSMigratePersistentStoresAutomaticallyOption = 1;
NSPersistentCloudKitContainerOptionsKey = "<NSPersistentCloudKitContainerOptions: 0x6000021035c0>";
NSPersistentHistoryTrackingKey = 1;
NSPersistentStoreMirroringOptionsKey = {
NSPersistentStoreMirroringDelegateOptionKey = "<NSCloudKitMirroringDelegate: 0x600003d00000>";
};
NSPersistentStoreRemoteChangeNotificationOptionKey = 1;
}
CoreData: debug: CoreData+CloudKit: -[NSCloudKitMirroringDelegate observeChangesForStore:inPersistentStoreCoordinator:](423): <NSCloudKitMirroringDelegate: 0x600003d00000>: Observing store: <NSSQLCore: 0x107a0be80> (URL: file:///~/Library/Developer/CoreSimulator/Devices/F475D0D5-EA93-498B-B7C5-007160ACDA56/data/Containers/Shared/AppGroup/C5337C45-86EF-4D32-80B8-E89D28A2336E/containerName.sqlite)
CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _setUpCloudKitIntegration:](584): <NSCloudKitMirroringDelegate: 0x600003d00000>: Successfully enqueued setup request: <NSCloudKitMirroringDelegateSetupRequest: 0x600002129ae0> CFEDB8FA-CFBB-46CD-A2F7-5E1C64EFDEA6
CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate checkAndExecuteNextRequest](3535): <NSCloudKitMirroringDelegate: 0x600003d00000>: Checking for pending requests.
CoreData: CloudKit: CoreData+CloudKit: -[NSCloudKitMirroringDelegate checkAndExecuteNextRequest]_block_invoke(3548): <NSCloudKitMirroringDelegate: 0x600003d00000>: Executing: <NSCloudKitMirroringDelegateSetupRequest: 0x600002129ae0> CFEDB8FA-CFBB-46CD-A2F7-5E1C64EFDEA6
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](452): Skipping migration for 'ANSCKDATABASEMETADATA' because it already has a column named 'ZLASTFETCHDATE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](510): Skipping migration for 'ANSCKMETADATAENTRY' because it already has a column named 'ZDATEVALUE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](452): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZLASTFETCHDATE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](468): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZSUPPORTSFETCHCHANGES'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](468): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZSUPPORTSATOMICCHANGES'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](468): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZSUPPORTSRECORDSHARING'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](468): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZSUPPORTSZONESHARING'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSIMPORT'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSRECOVERYFROMZONEDELETE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSRECOVERYFROMUSERPURGE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZENCODEDSHAREDATA'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSSHAREUPDATE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSSHAREDELETE'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSRECOVERYFROMIDENTITYLOSS'
CoreData: debug: CoreData+CloudKit: -[PFCloudKitMetadataModelMigrator calculateMigrationStepsWithConnection:error:](486): Skipping migration for 'ANSCKRECORDZONEMETADATA' because it already has a column named 'ZNEEDSNEWSHAREINVITATION'
The errors I am getting back from trying to initialize the store are these:
Error fetching user record ID: <CKError 0x600000c8cf60: "Bad Container" (1014); "Couldn't get container configuration from the server for container "containerName"">
error: CoreData+CloudKit: -[PFCloudKitSetupAssistant _checkUserIdentity:](1571): <PFCloudKitSetupAssistant: 0x600002620120>: Identity fetch failed with unknown error: <CKError 0x600000ca0000: "Bad Container" (5/1014); "Couldn't get container configuration from the server for container "containerName"">
error: CoreData+CloudKit: -[NSCloudKitMirroringDelegate _performSetupRequest:]_block_invoke(1232): <NSCloudKitMirroringDelegate: 0x600003d00000>: Failed to set up CloudKit integration for store: <NSSQLCore: 0x107a0be80> (URL: file:///~/Library/Developer/CoreSimulator/Devices/F475D0D5-EA93-498B-B7C5-007160ACDA56/data/Containers/Shared/AppGroup/C5337C45-86EF-4D32-80B8-E89D28A2336E/containerName.sqlite)
Obviously, I am missing something, but I have no idea what.
Okay, it turns out this is the line that was incorrect:
description.cloudKitContainerOptions = NSPersistentCloudKitContainerOptions(
containerIdentifier: CDConstants.containerName
)
The issue is I was putting the local container name in, instead of the iCloud container name. So, instead of localContainerName
, for example, it should have been iCloud.com.app. localContainerName
.
Thanks to this answer: https://stackoverflow.com/a/64359268/7129318 for guiding me in the correct direction.