Search code examples
iosswiftmacoscloudkitckquery

CKQuery Perform Only Fetches Records That Are Created Before Application Is Launched


I have iOS and macOS applications that I have been working on. With the iOS app, the user sends data to iCloud Drive while they use the macOS counterpart to receive data. The following lines of code come from the macOS application.

func completionPopulateDataFromCloud(uuid: String ,completionHandler: @escaping (Bool) -> (Void)) -> Void {
    DispatchQueue.global().async() {
        // Start Process //
        let cloudContainer = CKContainer(identifier: "whatever...")
        let privateDB = cloudContainer.privateCloudDatabase
        let predicate = NSPredicate(format: "uuid = %@", uuid)
        let query = CKQuery(recordType: "myRecords", predicate: predicate)
        query.sortDescriptors = [NSSortDescriptor(key: "date", ascending: false)]
        privateDB.perform(query, inZoneWith: nil) { records, error in
            guard let records = records else {
                completionHandler(false)
                return
            }

            DispatchQueue.main.async() {
                [weak self] in
                guard let strongSelf = self else { return }

                if records.count == 0 {
                } else {
                    let record = records[0]
                    let recordID = record.recordID.recordName
                    ...
                    ...
                    completionHandler(true)
                }
            }
        }
    }
}

So I just sort out a number of records with the date and get the latest record instead of getting all records.

The thing is that the application won't receive records that have been uploaded to iCloud Drive after the application is launched. Even when I wait for a few minutes, the application won't get the latest. If I quit the application and then relaunch it again, it will get the latest. Is that how things are supposed to work? I hope not. Is there some trick that I'm not aware of? Thanks.

p.s. I have read this topic. I don't think it's related to mine.


Solution

  • The usual way is to use a custom record zone. Create a CKRecordZoneSubscription and fetch the changes with CKFetchRecordZoneChangesOperation when the application launches. Handle and save the CKServerChangeToken to maintain the current state.

    While the app is running you get notified by push notifications about changes.

    Please watch the WWDC videos about CloudKit for more information.