Configuration
#
Record Zone IDIn 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 syncA 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 subscriptionCloudKit 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 notificationsCloudKitSynchronizer
also posts other notifications when it's syncing.
#
SyncOnly 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 compatibilityIf 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 sizeBy 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 configurationModel 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 policyServer, 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 processingIt 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 DataBy default Data
properties are uploaded using CKAsset
, but you can force the use of Data
by setting:
public var forceDataTypeInsteadOfAsset: Bool
#
hasChangesModel 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.
#
EncryptionStarting 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"]}