如何严格限制CloudKit查询结果数量至指定条数?
如何让CloudKit严格返回最多150条记录?
场景与问题
我有一个包含1000条记录的CloudKit数据库,需要获取其中150条记录,但遇到以下情况:
- 默认情况下,CloudKit会返回100条记录及一个游标,使用游标获取下一批的数量无保障(可能返回200条)
resultsLimit设置的返回数量并非固定,服务器会根据负载调整,比如首次仅返回30条,第二次再返回30条- 若通过循环获取下一批数据,最终会得到全部1000条记录
以下是我设置resultsLimit: 75的循环测试代码,当前会返回全部1000条记录:
func fetchRecords() async throws -> [CKRecord] { let predicate = NSPredicate(value: true) let query = CKQuery(recordType: "MyRecordType", predicate: predicate) query.sortDescriptors = [NSSortDescriptor(key: "datePublished", ascending: false)] var records: [CKRecord] = [] var (matchResults, queryCursor) = try await CKContainer(identifier: "iCloud.MyDB").publicCloudDatabase.records(matching: query, resultsLimit: 75) records.append(contentsOf: matchResults .compactMap { _, result in try? result.get()} .compactMap { $0 }) while let cursor = queryCursor { (matchResults, queryCursor) = try await CKContainer(identifier: "iCloud.MyDB").publicCloudDatabase.records(continuingMatchFrom: cursor, resultsLimit: 75) records.append(contentsOf: matchResults .compactMap { _, result in try? result.get()} .compactMap { $0 }) } print("Will return \(records.count) CloudKit records") return records }
请问是否存在方法可让CloudKit严格返回最多150条记录(可分批),还是需要先获取更多数据后在Swift代码中手动筛选150条?
解决方案
CloudKit无法严格保证每次返回指定数量的记录,也无法让服务器主动停止在150条记录的节点上——因为resultsLimit只是服务器的参考值,实际返回条数会受服务器负载、数据分布等因素影响。
但你可以在客户端逻辑中精准控制最终获取的记录总数,不需要获取多余数据:在每次获取到新记录后,检查累计总数是否达到150,若达到则直接终止循环,并且截断超出的部分(如果单次返回的记录导致总数超过150)。
修改后的代码如下:
func fetchMax150Records() async throws -> [CKRecord] { let targetCount = 150 let predicate = NSPredicate(value: true) let query = CKQuery(recordType: "MyRecordType", predicate: predicate) query.sortDescriptors = [NSSortDescriptor(key: "datePublished", ascending: false)] var records: [CKRecord] = [] var (matchResults, queryCursor) = try await CKContainer(identifier: "iCloud.MyDB").publicCloudDatabase.records(matching: query, resultsLimit: targetCount) // 处理首次返回的记录 let newRecords = matchResults.compactMap { _, result in try? result.get() } let remaining = targetCount - records.count if newRecords.count <= remaining { records.append(contentsOf: newRecords) } else { records.append(contentsOf: newRecords.prefix(remaining)) // 已经达到目标,直接返回 print("Will return \(records.count) CloudKit records") return records } // 循环获取下一批,直到达到目标或无更多数据 while let cursor = queryCursor, records.count < targetCount { let remaining = targetCount - records.count (matchResults, queryCursor) = try await CKContainer(identifier: "iCloud.MyDB").publicCloudDatabase.records(continuingMatchFrom: cursor, resultsLimit: remaining) let newRecords = matchResults.compactMap { _, result in try? result.get() } if newRecords.count <= remaining { records.append(contentsOf: newRecords) } else { records.append(contentsOf: newRecords.prefix(remaining)) } } print("Will return \(records.count) CloudKit records") return records }
代码说明
- 先定义目标数量
targetCount = 150,每次请求时,将resultsLimit设置为当前还需要的记录数(避免获取多余数据) - 每次处理新返回的记录时,检查是否会超出目标数量,若超出则只取需要的部分,直接终止流程
- 循环过程中,只要累计记录数达到150,就停止后续的游标请求
这种方式既不会获取多余的记录,也能精准控制最终返回的记录数不超过150条。
内容的提问来源于stack exchange,提问作者Stan
相关产品推荐
相关产品推荐

