I'm storing a record with field name "Folders" using an await for CloudKit API function CKDatabase.modifyRecords(...). To ensure my UI reflects the CloudKit data properly I then do an await for CKDatabase.records(matching: CKQuery).
The retrieved records do not reflect the addition of the new record unless I insert a "Task.sleep" call of at least 1 or 2 seconds between the modifyRecords and the records call. My guess is that the CloudKit server is doing indexing or other processing that doesn't finish until after the "records(matching:) call. So how do I query the database at the correct time to reflect the change? Do I need to be using CKSubscription?
Here's a simplified version of the code:
class ExampleManager: ObservableObject {
@Published var libraryItems: [LibraryItem] = []
var db: CKDatabase {
let container = CKContainer(identifier: "abcde")
return container.publicCloudDatabase
}
// a UI button will cause this function to be called
@MainActor
func addFolder(_ name: String) async {
let record = CKRecord(recordType: "Folder")
record.setValuesForKeys(["name": name])
do {
try await db.modifyRecords(saving: [record], deleting: [])
try await Task.sleep(nanoseconds: 2_000_000_000) // Why?
libraryItems = await fetchFolders()
} catch { /* handle errors */ }
}
@MainActor
func fetchFolders() async -> [LibraryItem] {
var folderInfo = [LibraryItem]()
let predicate = NSPredicate(value: true)
let queryAll = CKQuery(recordType: "Folder", predicate: predicate)
do {
let (matchResults, _) = try await db.records(matching: queryAll)
for mr in matchResults {
let (ckRecordID, result) = mr
switch result {
case .success(let record):
let name = record["name"] as! String
folderInfo.append(LibraryItem(name, cloudRecordID: ckRecordID))
case .failure: /* handle error */ break
}
}
} catch { /* handle error */ }
return folderInfo
}
}