CKSyncEngine: Duplicate FetchedRecordZoneChanges & Sync Handling Questions

Hi everyone,

I've recently implemented CKSyncEngine in my app, and I have two questions regarding its behavior:

  1. Duplicate FetchedRecordZoneChanges After Sending Changes:

I’ve noticed that the engine sometimes receives a FetchedRecordZoneChanges event containing modifications and deletions that were just sent by the same device a few moments earlier. This event arrives after the SentRecordZoneChanges event, and both events share the same recordChangeTag, which results in double-handling the record.

Is this expected behavior? I’d like to confirm if this is how CKSyncEngine works or if I might be overlooking something.

  1. Handling Initial Sync with a "Sync Screen":

When a user opens the app for the first time and already has data stored in iCloud, I need to display a "Sync Screen" temporarily to prevent showing partial data or triggering abrupt, rapid UI changes.

I’ve found that canceling current operations, then awaiting sendChanges() and fetchChanges() works well to ensure data is fully synced before dismissing the sync screen:

displaySyncScreen = true
await syncEngine.cancelOperations()
try await syncEngine.sendChanges()
try await syncEngine.fetchChanges()
displaySyncScreen = false

However, I’m unsure if canceling operations like this could lead to data loss or other issues. Is this a safe approach, or would you recommend a better strategy for handling this initial sync state?

I’ve noticed that the engine sometimes receives a FetchedRecordZoneChanges event containing modifications and deletions that were just sent by the same device a few moments earlier. This event arrives after the SentRecordZoneChanges event, and both events share the same recordChangeTag, which results in double-handling the record.

CloudKit isn't supposed to deliver a change event for the device that made the change, if no other change from another peer happened at the same time. If you see otherwise, I’d suggest that you file a feedback report and share your report ID here for folks to track.

I’m unsure if canceling operations like this could lead to data loss or other issues.

I don't see that an issue. cancelOperations() cancels the operations that are currently in-progress or pending. When it determines appropriate, CKSyncEngine will continue to sync based on the state.

However, I'd think that you should present your UI based on your local cache, and only update the UI after getting changes from CKSyncEngine and merging them to your local cache, rather than proactively fetch changes from the server side. Will there be anything wrong if you go with this pattern?

Best,
——
Ziqiao Chen
 Worldwide Developer Relations.

CKSyncEngine: Duplicate FetchedRecordZoneChanges & Sync Handling Questions
 
 
Q