Multiplatform CoreData or SwiftData with CloudKit – Checklist

If you want to use CoreData or SwiftData with CloudKit and build for iOS and Mac (and probably other Apple platforms) here are the things you might have to consider (i.e. things I learned the hard way):

CloudKit Environment

Xcode Debug Build & Run uses the Development environment on CloudKit. Testflight and app store releases use the Production environment. There are ways to use production environment for debug builds, but not the other way around.

Keep Environments separate

But if you both test and use your app on the same machine (hello indie Mac developer), all these use the same local ~/Library/Containers folder. This will create a big mess with your data, syncing the same local data with different CloudKit environments.

To prevent this mess I configure seperate Bundle IDs for Release and Debug builds (e.g. “ch.zoziapps.leviathan” and “ch.zoziapps.leviathan.debug”).

This creates distinct folders in ~/Libray/Containers and makes it easier to separate test and productive use of your app.

Make sure to do this for all of your apps targets.

Attention when profiling!

Environment separation is tricky as soon as you Profile your app with Instruments. The Profile target by default uses the ‘release’ build configuration because this leads to more realistic measurements. But on the CloudKit environment remains Production! This means, as soon as you profile your app, your local app data gets contaminated with development-container data, which in turn contaminates your production-data the next time you launch the executable normally.

One way to address the issue is to edit the profile scheme to use the ‘debug’ configuration.

App Extensions/Embedded Targets and App Groups

Speaking of all targets: If you have an extension that needs to access the same data, you have to place your container in an AppGroup. I would create two separate AppGroups (again, a release and a debug version) and initialize the container with the correct app group:

static func createModelContainer() -> ModelContainer {
		
	let schema = Schema([
		Item.self,
	])
	
	#if DEBUG
	let groupName = "group.loremipsum.debug"
	#else
	let groupName = "group.loremipsum"
	#endif
		
	let modelConfiguration = ModelConfiguration(
		schema: schema,
		isStoredInMemoryOnly: false,
		groupContainer: .identifier(groupName),
		cloudKitDatabase: .automatic)
		
	do {
		return try ModelContainer(for: schema, configurations: [modelConfiguration])
	} catch {
		fatalError("Could not create ModelContainer: \(error)")
	}
}

Both app groups need to be checked in the Capabilities section.

Configure CloudKit Framework

Also make sure that CloudKit appears under “Frameworks, Libraries and Embedded Content” (options “Always Used” and “Do not embed”) otherwise CloudKit won’t sync, at least on the Mac (I think). (Thank you JTostitos in this Reddit thread).

Deploy Schema

Don’t forget to deploy the schema (and later changes) to production in the iCloud Console.

2 thoughts on “Multiplatform CoreData or SwiftData with CloudKit – Checklist”

  1. @stefan nice article. I did not use these services so far. But is it possible to have a single app and somehow decide during runtime where you sync to? Having to separate apps is nice but it creates so much overhead. And when you want to create a service with multiple backends it would also help. Although I assume then I should not use CloudKit in the first place at all.

  2. It is possible to enable or disable the CloudKit sync at runtime (when you create the Model). If you are using SwiftData it is as simple as passing .automatic or .none for the ModelConifguration’s cloudKitDatabase argument.

Leave a Reply

Your email address will not be published. Required fields are marked *

To respond on your own website, enter the URL of your response which should contain a link to this post's permalink URL. Your response will then appear (possibly after moderation) on this page. Want to update or remove your response? Update or delete your post and re-enter your post's URL again. (Find out more about Webmentions.)