One Logo Pool Ball
CloudKit · IOS API REFERENCE

CKSyncEngine

class · iOS 17.0+ · SDK 27.1

final class CKSyncEngine

An object that manages the synchronization of local and remote record data. Use ``CKSyncEngine-5sie5`` to handle your app's CloudKit sync operations and benefit from the performance and reliability it provides. To use the class, create an instance early in your app's launch process and specify a database to sync. Thereafter, and depending on good system conditions, the sync engine periodically pushes and pulls database and record zone changes on the app's behalf. To participate in those sync operations and to provide the engine with the changes to send, create a type that conforms to ``CKSyncEngineDelegate-1q7g8`` and assign an instance of it to the engine's configuration. You can have multiple instances of ``CKSyncEngine-5sie5`` in a single process, each targeting a different database. For example, you may have one syncing a person's private database and another syncing their shared database. Because periodic sync relies on good system conditions — adequate battery charge, an active network connection, a signed-in iCloud account, and so on — the engine's sync schedule is indeterminate. If you need to sync immediately, like when your app requires it has the most recent changes before continuing, use the ``fetchChanges(_:)`` and ``sendChanges(_:)`` methods. The sync engine uses an opaque type to track its internal state, and it's your responsibility to persist that state to disk and make it available across app launches so the engine can function properly. For more information, see ``CKSyncEngineDelegate-1q7g8/handleEvent(_:syncEngine:)`` and ``Event/StateUpdate``. ``CKSyncEngine-5sie5`` requires the CloudKit and Remote notifications entitlements. For more information, see <doc://com.apple.documentation/documentation/xcode/configuring-icloud-services> and <doc://com.apple.documentation/documentation/xcode/configuring-background-execution-modes>. - Important: Don't use ``CKSyncEngine-5sie5`` to sync your app's public database. ### Send changes to iCloud A sync engine requires you to tell it about any changes to send, which you do by invoking the ``State/add(pendingDatabaseChanges:)`` and ``State/add(pendingRecordZoneChanges:)`` methods on the engine's ``state`` property. If there are no scheduled sync operations when you invoke these methods, the engine automatically schedules one. Database changes don't require any additional input, but the sync engine does expect you to provide the individual record zone changes — in batches — and return them from your delegate's implementation of ``CKSyncEngineDelegate-1q7g8/nextRecordZoneChangeBatch(_:syncEngine:)``. After the engine sends the changes, it notifies your delegate about their success (or failure) by dispatching ``Event/sentDatabaseChanges(_:)`` and ``Event/sentRecordZoneChanges(_:)`` events. ### Batches The sync engine sends record zone changes to the server in batches, where each batch corresponds to a single network request. After your app registers pending changes through ``State/add(pendingRecordZoneChanges:)``, the engine drives a send operation by repeatedly invoking ``CKSyncEngineDelegate-1q7g8/nextRecordZoneChangeBatch(_:syncEngine:)`` to gather those changes into batches and sending each batch as one request. It keeps asking for batches until your delegate returns `nil` or the operation is cancelled, meaning a single send operation may span many batches. Each batch is bounded by the server's per-request limit of 250 records (saves plus deletes combined); a batch that exceeds the limit fails with ``CKError/Code/limitExceeded`` and the sync engine treats it like any other send failure. To stay within the limit automatically, build your batches with ``RecordZoneChangeBatch/init(pendingChanges:recordProvider:)``, which walks your pending changes in order and stops once the batch is full. Any changes that don't fit stay in ``State/pendingRecordZoneChanges``, so the engine picks them up on the next call. After each batch finishes, the engine dispatches a ``Event/sentRecordZoneChanges(_:)`` (or ``Event/sentDatabaseChanges(_:)``, for database changes) event that describes only the records in that batch, so a single send operation produces one sent-changes event per batch rather than a single event for the whole operation. When your delegate builds a batch, include only changes that fall within the scope specified by ``SendChangesContext/options`` on the provided context. Returning changes outside that scope causes the send to fail with ``CKError/invalidArguments``. ### Fetch changes from iCloud By default, a sync engine attempts to discover an existing ``CKDatabaseSubscription`` for the associated database and uses that to receive silent notifications about remote record changes. If the engine doesn't find a subscription, it automatically creates one to use. On receipt of a notification, the engine schedules a sync operation to fetch the related changes. When that operation runs, the engine dispatches a ``Event/willFetchChanges(_:)`` event to your delegate. As it receives fetched changes, the engine dispatches ``Event/fetchedDatabaseChanges(_:)`` and ``Event/fetchedRecordZoneChanges(_:)``, accordingly. After the operation finishes, the sync engine notifies your delegate by dispatching a ``Event/didFetchChanges(_:)`` event. You handle all dispatched events in your delegate's implementation of ``CKSyncEngineDelegate-1q7g8/handleEvent(_:syncEngine:)``. ### Sync Scheduling #### Automatic sync By default, the sync engine automatically schedules sync tasks on your behalf. If the user is signed in, the device has a network connection, and the system is generally in a good state, these scheduled syncs happen relatively quickly. However, if the device has no network, is low on power, or is otherwise under a heavy load, these automatic syncs might be delayed. Similarly, if the user isn't signed in to an account, the sync engine won't perform any sync tasks at all. #### Manual sync There may be some cases where you want to manually trigger a sync. For example, if you have a pull-to-refresh UI, you can call ``fetchChanges(_:)`` to tell the sync engine to fetch immediately. Or, if you have a "backup now" UI, you can call ``sendChanges(_:)`` to send to the server immediately. ### Error Handling There are some transient errors that the sync engine handles automatically behind the scenes. The sync engine retries the operations for these transient errors automatically when it makes sense to do so. Specifically, the sync engine will handle the following errors on your behalf: * ``CKError/Code/notAuthenticated`` * ``CKError/Code/accountTemporarilyUnavailable`` * ``CKError/Code/networkFailure`` * ``CKError/Code/networkUnavailable`` * ``CKError/Code/requestRateLimited`` * ``CKError/Code/serviceUnavailable`` * ``CKError/Code/zoneBusy`` When the sync engine encounters one of these errors, it waits for the system to be in a good state, and tries again. For example, if the server sends back a ``CKError/Code/requestRateLimited`` error, the sync engine respects this throttle and tries again after the error's retry-after time. `CKSyncEngine` does _not_ handle errors that require application-specific logic. For example, if you try to save a record and get a ``CKError/Code/serverRecordChanged``, you need to handle that error yourself. There are plenty of errors that the sync engine cannot handle on your behalf, see ``CKError`` for a list of all the possible errors. ### Accounts `CKSyncEngine` monitors for account status, and it only syncs if there's an account signed in. Because of this, you can initialize your `CKSyncEngine` at any time, regardless of account status. If there is no account, or if the user disabled sync in settings, the sync engine stays dormant in the background. Once an account is available, the sync engine starts syncing automatically. The sync engine listens for when the user signs in or out of their account. When it notices an account change, it sends an ``Event/accountChange(_:)`` to your delegate. It's your responsibility to react appropriately to this change and update your local persistence. - Tip: A sample code project for ``CKSyncEngine-5sie5`` is available on GitHub here: [CloudKit Samples: CKSyncEngine](https://github.com/apple/sample-cloudkit-sync-engine).

Members (7)

get · iOS 17.0+

description

TypeScript
get description(): string
Swift declaration
final var description: String { get }

The textual description of the engine that's suitable for logging.

method · iOS 17.0+

sendChanges

TypeScript
sendChanges(options?: CKSyncEngine_SendChangesOptions): Promise<void>
Swift declaration
final func sendChanges(_ options: CKSyncEngine.SendChangesOptions = .init()) async throws

Sends pending local changes to the server. - Parameter options: The options to use when sending changes. For more information, see ``CKSyncEngine-5sie5/SendChangesOptions``. Use this method to request the sync engine sends all pending local changes to the server before your app continues. This isn't necessary in normal use, as the engine automatically syncs your app's records. It is useful, however, in scenarios where you require greater control over sync, such as a "Backup now" button or unit tests. - Note: ``sendChanges(_:)`` returns only after your sync delegate finishes processing all related send events. - Throws: An error if the send operation fails. Common errors include network failures, authentication issues, conflicts, or server-side problems.

method · iOS 17.0+

fetchChanges

TypeScript
fetchChanges(options?: CKSyncEngine_FetchChangesOptions): Promise<void>
Swift declaration
final func fetchChanges(_ options: CKSyncEngine.FetchChangesOptions = .init()) async throws

Fetches pending remote changes from the server. - Parameter options: The options to use when fetching changes. For more information, see ``CKSyncEngine-5sie5/FetchChangesOptions``. Use this method to request the sync engine immediately fetches all pending remote changes before your app continues. This isn't necessary in normal use, as the engine automatically syncs your app's records. It is useful, however, in scenarios where you require more control over sync, such as pull-to-refresh or unit tests. - Note: ``fetchChanges(_:)`` returns only after your sync delegate finishes processing all related fetch events. - Throws: An error if the fetch operation fails. Common errors include network failures, authentication issues, or server-side problems.

method · iOS 17.0+

cancelOperations

TypeScript
cancelOperations(): Promise<void>
Swift declaration
final func cancelOperations() async

Cancels any in-progress or pending sync operations. The sync engine processes cancellation requests asynchronously, meaning it's possible for in-progress operations to complete even after this method returns.

get · iOS 17.0+

state

TypeScript
get state(): CKSyncEngine_State
Swift declaration
final var state: CKSyncEngine.State { get }

A collection of state properties used to efficiently manage sync engine operation. - SeeAlso: ``CKSyncEngine-5sie5/State``

get · iOS 17.0+

database

TypeScript
get database(): CKDatabase
Swift declaration
final var database: CKDatabase { get }

The associated database. Multiple sync engines can run in the same process, each targeting a different database. For example, you may use one sync engine for a person's private database and another for their shared database.

init · iOS 17.0+

init

TypeScript
static init(configuration: CKSyncEngine_Configuration): CKSyncEngine
Swift declaration
init(_ configuration: CKSyncEngine.Configuration)

Creates a sync engine with the specified configuration. - Parameter configuration: The attributes of the new sync engine, such as the associated database and the object to use as the engine's delegate. For more information, see ``CKSyncEngine-5sie5/Configuration``.

Skipped declarations

No declarations were skipped in this snapshot.

All CloudKit types →