Skip to main content


Record Zone ID#

In the case of the private synchronizer you can optionally specify the name of the CloudKit record zone to use for synchronization. Otherwise the default will be used:

CKRecordZone.ID(zoneName: "QSCloudKitCustomZoneName", ownerName: CKCurrentUserDefaultName)

When to sync#

A common question is when to trigger a new sync process. Model adapters will post the ModelAdapterHasChangesNotification notification when they detect new changes, so one option is to listen for that to either trigger the sync automatically or to update some UI element to let the user know, in case your app lets the user initiate the sync.

This notification is posted only once, when the model adapter goes from "synced" to "changed", rather than for every change that happens.

CloudKit subscription#

CloudKit supports push notifications to let your app know when changes have been uploaded from another device. You can subscribe for changes in a database:

synchronizer.subscribeForChangesInDatabase { error in  // subscribed}

Both the private and shared databases support database subscriptions.

You can also subscribe for changes in a record zone:

if let adapter = synchronizer.modelAdapters.first {  synchronizer.subscribeForChanges(in: adapter.recordZoneID) { error in    // subscribed  }}

Only the private database supports record zone subscriptions.

According to Apple you do not need to explicitly enable the Push Notification capability for your app, but you do need to register for remote notifications in your app:

func application(_ application: UIApplication,           didFinishLaunchingWithOptions launchOptions:           [UIApplicationLaunchOptionsKey: Any]?) -> Bool {   // Override point for customization after application launch.                  UIApplication.shared.registerForRemoteNotifications()   return true}
func application(_ application: UIApplication, didReceiveRemoteNotification userInfo: [AnyHashable : Any]) {  // Do something here, or use the newer UNUserNotificationCenterDelegate methods}

For more information see the Apple documentation

Other notifications#

CloudKitSynchronizer also posts other notifications when it's syncing.


Only one sync process can be active at the same time. If you call synchronize while CloudKitSynchronizer is already doing so you will receive an alreadySyncing error.

Model compatibility#

If you create a new version of your Core Data or Realm model you might want to avoid versions of your app running older versions of the model to get any records that were created under the new model. For that, you can use:

public var compatibilityVersion: Int

When a new model version is created, you can increase the compatibilityVersion on the synchronizer. If a synchronizer receives a record from CloudKit that was created by a newer version, the sync process will terminate with a higherModelVersionFound error. Do note that the opposite is not true, newer versions of your app might still receive records created by the older version, if the user upgraded the app while it was not fully synced, for example.

Batch size#

By default CloudKitSynchronizer will use a batch size of 200. You can change that number using:

public var batchSize: Int

Regardless of the initial value, if CloudKitSynchronizer ever receives a CKError.Code.limitExceeded from CloudKit it will reduce the batch size for future operations.

Adapter configuration#

Model adapters are accessible via the modelAdapters property in CloudKitSynchronizer, and you can perform further customization on them if you need. A synchronizer for the private database will commonly only have one model adapter, but synchronizers for the shared database will have one model adapter for each record zone that was shared with this user.

Merge policy#

Server, local or custom policies are available

A custom merge policy is possible by providing a conflict resolution delegate to the model adapter. Core Data, Realm

Custom record processing#

It is possible for your app to customize the way records are created and handled by providing a record processing delegate to your model adapter. This will let you do things like:

Remove specific fields from your records before they're sent to CloudKit. Read and write files from the file system to send them as CKAssets, if your model contains references to files in the file system rather than the data itself. Core Data Realm

CKAsset as Data#

By default Data properties are uploaded using CKAsset, but you can force the use of Data by setting:

public var forceDataTypeInsteadOfAsset: Bool


Model adapters also have a hasChanges property that you can check to tell if there are any changes that have not been uploaded to iCloud yet.


Starting on iOS 15 and OSX 12, CloudKit supports encrypted values for some of the fields in your objects. You can adopt this with SyncKit by making your model conform to the EncryptedObject protocol to return the names of the fields that should be encrypted:

static func encryptedFields() -> [String] {  ["secretField", "secretField2"]}