I have some kind of CloudKit indexing issue. When I save records to iCloud using CKModifyRecordsOperation, modifyRecordsCompletionBlock returns no errors. When I query those records using NSPredicate(value: true) or Dashboard, most of the time it misses one or two records.
So say I upload 5 records (no errors), wait some time (~15 secs) to make sure that indexes are updated, and then query them (through dashboard or app's CKQueryOperation). Most of the time it will show 4 records out 5. Again, no errors. Records are in privateDB in customZone.
Here is what's strange: I'm always able to get records that query didn't return by manually typing recordNames in Dashboard (development) under 'Fetch' menu. So it stores them, just doesn't query. When I delete indexes in a dashboard and reassign them, dashboard query will start to return all the results (with previously omitted records too), but after a few more uploads, some will start to be missing from query again.
Here is my CKModifyRecordsOperation:
let operation = CKModifyRecordsOperation(recordsToSave: records, recordIDsToDelete: [])
operation.modifyRecordsCompletionBlock =
{ [weak self] savedRecords, deletedRecordIDs, error in
guard error == nil else { // no errors here ... }
...
//for each item uploaded to iCloud, mark as synced
if let savedRecords = savedRecords{ // all attempted to save records are here
PendingCloudOperations.shared.markAsUploaded(
savedRecords.map{ $0.recordID.recordName })
}
completion(...)
}
operation.savePolicy = .changedKeys // tried .allKeys too
operation.qualityOfService = .userInitiated
self.privateDB.add(operation)
I experimented with record fields (originally date, asset, and reference) trying to see if any of the fields make a problem. But even if I remove all field's (creating a record with no extra fields, just system meta), problem persists. I didn't include CKQueryOperation code, because Dashboard acts same way as the app.
Any ideas?
EDIT: Here are bare-bones of my fetching function:
var receipts:[FS_Receipt] = []
let query = CKQuery(recordType: myRecordType, predicate: NSPredicate(value: true))
let operation = CKQueryOperation(query: query)
//completion block
operation.queryCompletionBlock = { [weak self] cursor, error in
guard error == nil else {
// doesn't have any errors here
}
completion(...)
}
operation.recordFetchedBlock = { record in
// doesn't return all records here most of the time.
}
operation.qualityOfService = .userInitiated // without this, 'no internet' will NOT return error
operation.resultsLimit = 5000
operation.zoneID = customZoneID
self.privateDB.add(operation)
}