11

我想从公共数据库中提取大约 500 条“访问”记录。CloudKit 一次只给你 100 条记录,所以我只使用下面的 CKQueryCursor 来获取我想要的所有记录。

func fetchVisits(_ cursor: CKQueryCursor? = nil) {
    print("fetchVisits \(cursor)")
    var operation: CKQueryOperation!
    if let cursor = cursor {
        operation = CKQueryOperation(cursor: cursor)
    } else {
        let query = CKQuery(recordType: "Visit", predicate: NSPredicate(format: "Client IN %@ AND ANY Students IN %@", visitClients, visitStudents))
        operation = CKQueryOperation(query: query)
    }
    operation.recordFetchedBlock = {
        (record) in
        totalVisits.append(record)
    }
    operation.queryCompletionBlock = {
        (cursor, error) in
        if let error = error {
            //handle error
        } else if let cursor = cursor {
            self.fetchVisits(cursor)
        } else {
            //all done!
        }
    }
    CKContainer.default().publicCloudDatabase.add(operation)
}

我将函数称为:

fetchVisits()

效果很好,它可以获得我需要的所有访问。控制台日志

fetchVisits nil
fetchVisits Optional(<CKQueryCursor: 0x174228140; id=4bb7887c326fc719, zone=(null)>)
fetchVisits Optional(<CKQueryCursor: 0x17422a320; id=f67fb25669486da9, zone=(null)>)
fetchVisits Optional(<CKQueryCursor: 0x174228380; id=7e87eb8b7cfe1a74, zone=(null)>)
fetchVisits Optional(<CKQueryCursor: 0x17422cc80; id=e77e47ef2b29c8a4, zone=(null)>)

但问题是现在我想在按下按钮时刷新,现在它给了我这个错误:

“服务不可用”(6/2022);"请求失败,http 状态码 503"; 30.0 秒后重试

这很不言自明,我想我通过请求微不足道的 500 条记录来压倒服务器?所以我等待 30 秒并再次调用该函数,现在我得到了这个错误。

“超出限制”(27/2023);服务器消息 =“查询过滤器超出了值的限制:容器为 250

由于某种原因,我无法再次运行该功能。如果我重新启动应用程序,它会再次正常工作,但只是第一次。这个问题似乎特定于任何返回 CKQueryCursor 的表。我有其他我正在访问的表少于 100 条记录(因此光标为零),我可以多次提取这些表而不会出现任何问题。

4

3 回答 3

5

好的,所以我以前见过这个问题,我相信问题是 CloudKit 服务器上的一个错误。以我的经验,它与复杂的查询有关。

如果您尝试将谓词更改为:

NSPredicate(value: true)

或者甚至通过删除 ANY 部分来简化您现有的部分,这可能足以修复它。

于 2017-07-29T17:21:29.820 回答
1

在查询操作完成之前,您正在向 iCloud 请求更多 CKRecords。

...
operation.queryCompletionBlock = {
    (cursor, error) in
    if let error = error {
        //handle error
    } else if let cursor = cursor {
        self.fetchVisits(cursor)
    } else {
        //all done!
    }
}
...

函数self.fetchVisits(cursor)调用在完成块内完成,这意味着您在当前操作完成之前请求更多记录。

可能的解决方案是使用包含 CKQueryCursor 的闭包(completionHandler),当用户需要更多记录(滚动表或其他任何内容)时,您再次调用一个self.fetchVisits通过闭包收到的光标。

于 2017-07-27T10:34:16.950 回答
1

编辑:我想现在我找到了原因:

虽然我之前的回答(如下)是正确的,但它不适用于这个问题。
到目前为止,我遇到了问题中提到的两个服务器错误,并调查了情况。

我的设置如下:
我想根据谓词中指定的条件下载 iCloud 记录的子集:

let doNotDownloadIfOlderFormat = "NOT " + iCloudRecordKeyName + " IN %@"
let doNotDownloadIfOlderPredicate = NSPredicate.init(format: doNotDownloadIfOlderFormat, doNotDownloadIfOlder)  

这里,doNotDownloadIfOlder是一组自定义对象。

在某些测试用例中,它们的数量超过 300。我怀疑这可能是错误消息Query filter超出了值的限制:250 for container的原因。

因此我修改了我的代码:

let doNotDownloadIfOlderFormat = "NOT " + iCloudRecordKeyName + " IN %@"
let limit = min(doNotDownloadIfOlder.count, max)
let shortened = Set(Array(doNotDownloadIfOlder)[0 ..< limit])
let doNotDownloadIfOlderPredicate = NSPredicate.init(format: doNotDownloadIfOlderFormat, shortened)  

我将max测试值设置为 300 以下
。结果如下:

  • 最大值 <= 140:没有错误
  • 141 <= max <= 250:“服务不可用”(6/2022);"请求失败,http 状态码 503"; 30.0 秒后重试>
  • 最大值 > 250:“超出限制”(27/2023);服务器消息 =“查询过滤器超出了值的限制:容器为 250

显然,查询可能存在未记录的服务器限制。奇怪的数字 140 可能与我的自定义对象的大小有关。

上一个答案:

文档说 :

服务器可以随时更改其限制,但以下是一般准则:

  • 每个操作 400 个项目(记录或共享)
  • 每个请求 2 MB(不包括资产大小)

如果您的应用程序收到CKError.Code.limitExceeded它必须将操作分成两半并再次尝试这两个请求

于 2019-07-06T13:01:45.380 回答