Search code examples
swiftcloudkitckqueryckqueryoperation

Why will my CKQueryOperation only return a Cursor if the results limit is less than 1000?


CloudKit has about 2000 records that I am attempting to download. I cannot get all of them to download, I looked at CloudKit CKQueryOperation doesn't get all records to get more than 100 results. Now I can get upto 999 to download, but if I set the results limit to 1000 or more it will fail randomly between 80-500. Will I need to split these entries into different record types?

private func checkForCloudData() {
    let query = CKQuery(recordType: "myRecordType", predicate: .init(value: true))
    let op = CKQueryOperation(query: query)

    op.qualityOfService = .userInitiated
    op.queuePriority = .veryHigh
    op.resultsLimit = 999

    op.recordFetchedBlock = { record in
        // fetched record
    }

    op.queryCompletionBlock =  { cursor, err in

        if cursor != nil {
            print(cursor!)

            self.performOperation(withOperation: CKQueryOperation(cursor: cursor!))
        }

        if err == nil {
            // handle complete download
        } else {
            if (err as! CKError).code == .limitExceeded {
                if cursor != nil {
                    self.performOperation(withOperation: CKQueryOperation(cursor: cursor!))
                    return
                }
                let newOperation = CKQueryOperation(query: query)
                newOperation.resultsLimit = op.resultsLimit
                newOperation.queuePriority = .veryHigh
                newOperation.qualityOfService = .userInitiated
                newOperation.recordFetchedBlock = op.recordFetchedBlock
                newOperation.queryCompletionBlock = op.queryCompletionBlock

                self.performOperation(withOperation: newOperation)
            }
        }

    }

    self.performOperation(withOperation: op)
}

private func performOperation(withOperation operation: CKQueryOperation) {
        publicDB.add(operation)
}

Solution

  • I believe that 400 is the the limit for a single operation, so you need to use cursor to get more records, and keep on doing that while returned cursor is not nil.

    See how it is done in RxCloudKit library' RecordFetcher - https://github.com/maxvol/RxCloudKit/blob/master/RxCloudKit/RecordFetcher.swift