我正在使用 CloudKit 從使用 CKQuery 的私有資料庫中檢索記錄,在異步函式中使用 CKQueryOperation.queryResultBlock。我已經找到了幾個使用 queryCompletionBlock 的示例,但這些示例已被棄用并被 queryResultBlock 取代,關于如何實作它的可用檔案很少。只要不回傳查詢完成游標(<=100 條記錄),我的函式就可以很好地作業,但我無法弄清楚如何迭代它。
這是我正在使用的代碼:
public func queryRecords(recordType: CKRecord.RecordType, predicate: NSPredicate) async throws -> [CKRecord] {
var resultRecords: [CKRecord] = []
let db = container.privateCloudDatabase
let query = CKQuery(recordType: recordType, predicate: predicate)
let operation = CKQueryOperation(query: query)
let operationQueue = OperationQueue() // for > 100 records
operationQueue.maxConcurrentOperationCount = 1 // for > 100 records
operation.zoneID = zoneID
debugPrint("query for recordType=\(recordType) in zone \(zoneID.zoneName) with predicate \(predicate)")
return try await withCheckedThrowingContinuation { continuation in
operation.queryResultBlock = { result in
switch result {
case .failure(let error):
debugPrint(error)
continuation.resume(throwing: error)
case .success(let ckquerycursor):
debugPrint("successful query completion after \(resultRecords.count) record(s) returned")
if let ckquerycursor = ckquerycursor {
debugPrint("***** received a query cursor, need to fetch another batch! *****")
let newOperation = CKQueryOperation(cursor: ckquerycursor) // for > 100 records
newOperation.queryResultBlock = operation.queryResultBlock // for > 100 records
newOperation.database = db // for > 100 records
operationQueue.addOperation(newOperation) // for > 100 records
}
continuation.resume(returning: resultRecords)
}
}
operation.recordMatchedBlock = { (recordID, result1) in
switch result1 {
case .failure(let error):
debugPrint(error)
case .success(let ckrecord):
resultRecords.append(ckrecord)
}
}
db.add(operation)
}
}
我試圖實作類似示例中的代碼但沒有成功:上面的代碼導致致命錯誤“SWIFT TASK CONTINUATION MISUSE”作為該行
continuation.resume(returning: resultRecords)
顯然被多次呼叫(非法)。用“// for > 100 records”注釋的行代表我添加到迭代的代碼;其他一切都適用于 100 或更少的記錄集。
我是否需要迭代地呼叫 queryRecords 函式本身,如果它存在則傳遞查詢游標,或者是否可以像我在這里嘗試做的那樣將迭代操作添加到佇列中?
如果有人在使用 queryResultBlock(不推薦使用 queryCompletionBlock)之前這樣做過,請幫忙!謝謝!
uj5u.com熱心網友回復:
queryResultBlock在 Swift 5.5 中不需要。
我使用它是因為我的CKRecord型別總是與它們的 Swift 對應物命名相同。如果你愿意,你可以recordType: "\(Record.self)"用你的recordType來代替。
public extension CKDatabase {
/// Request `CKRecord`s that correspond to a Swift type.
///
/// - Parameters:
/// - recordType: Its name has to be the same in your code, and in CloudKit.
/// - predicate: for the `CKQuery`
func records<Record>(
type _: Record.Type,
predicate: NSPredicate = .init(value: true)
) async throws -> [CKRecord] {
try await withThrowingTaskGroup(of: [CKRecord].self) { group in
func process(
_ records: (
matchResults: [(CKRecord.ID, Result<CKRecord, Error>)],
queryCursor: CKQueryOperation.Cursor?
)
) async throws {
group.addTask {
try records.matchResults.map { try $1.get() }
}
if let cursor = records.queryCursor {
try await process(self.records(continuingMatchFrom: cursor))
}
}
try await process(
records(
matching: .init(
recordType: "\(Record.self)",
predicate: predicate
)
)
)
return try await group.reduce(into: [], =)
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/430554.html
