NSPersistentCloudkItContainer and iCloud synchronization speed issues

In our app, there is a scenario where we write and delete approximately 100MB of files to the iCloud server at once using NSPersistentCloudkItContainer(CoreData). While write, read, and delete operations are immediately reflected in the local database, there is a noticeable delay when accessing the CloudKit Database dashboard.

Here is the testing approach we have tried:

  • Data Insert Test

  1. Prepare around 100MB of data.

  2. Write the data to CoreData on device A.

  3. When launching the app on device B, it takes about 5 minutes for the data to be fully synchronized.
  • Data Deletion Test
  1. Remove all the added data on device A (immediately reflected in local storage.)

  2. After performing step 1, leaving device A idle takes about 3 minutes for the deletion to be reflected on device B.

  3. if the app is deleted on device A after step 1, deletion information does not reach device B. Upon reinstalling the app on device A, the deleted data reappears on device B (synchronized data).

The ongoing occurrence of these issues has raised several questions regarding cloud synchronization and synchronization speed:

  • Is the synchronization speed of the Testflight app the same as the one received from the AppStore?
  • Are there traffic limitations per account or device?
  • Despite different perceived speeds for each account or device, is there any factor influencing synchronization speed other than network conditions?

What does the code implementation look like that is responsible for the cloud sync?

Both methods experience delays when synchronizing a large amount of data at once.
We are using two methods:

  • During the initial installation, we call the below code to receive synchronization data and provide a user experience indicating that synchronization is in progress.

     public extension NSPersistentCloudKitContainer {
        func waitForCloudKitEvents(timeout: Int) async throws -> NSPersistentCloudKitContainer.Event? {
            let affectedStores = persistentStoreDescriptions
                .filter { description in
                    description.cloudKitContainerOptions != nil
                }
                .compactMap { description -> NSPersistentStore? in
                    guard let url = description.url else { return nil }
                    return persistentStoreCoordinator.persistentStore(for: url)
                }
    
            let context = newBackgroundContext()
            let request = NSPersistentCloudKitContainerEventRequest.fetchEvents(after: .distantPast)
            request.resultType = .events
            request.affectedStores = affectedStores     
    
            for seconds in 0...timeout {
                await Task.sleep(seconds: 1)
    
                let results: NSPersistentStoreResult = try context.execute(request)
    
                // find event.
                if let results = results as? NSPersistentCloudKitContainerEventResult,
                   let events = results.result as? [NSPersistentCloudKitContainer.Event],
                   let event = (events.first { $0.succeeded && $0.type == .import }) {
                    return event
                }
            }
    
            throw CoreDataError.cloudKitEventTimeOut
        }
    }
    
  • For regular data synchronization (upload, download), we use the typical approach of receiving synchronization data using CloudKitContainer and NSPersistentCloudKitContainer.eventChangedNotification.
    (We employ a structure similar to the Apple CoreData synchronization example.)

NSPersistentCloudkItContainer and iCloud synchronization speed issues
 
 
Q