CKQueryOperation queryCompletionBlock 只运行 3 次

Posted

技术标签:

【中文标题】CKQueryOperation queryCompletionBlock 只运行 3 次【英文标题】:CKQueryOperation queryCompletionBlock only runs 3 times 【发布时间】:2015-07-19 16:07:16 【问题描述】:

我正在尝试使用 CloudKit 和光标从我的 iCloud 公共数据库中下载一批记录。无论 resultsLimit 是如何设置的,代码对于前 3 次执行都可以正常工作,但第 4 个完成块永远不会执行。如果未设置 resultsLimit 我得到 300 条记录,如果设置为 50 我得到 150,如果设置为 5 我得到 15...

没有报告错误,并且该块似乎已添加但从未执行。平台是 OS X。这是有问题的代码:

        let queryOp = CKQueryOperation(query: query)
        queryOp.recordFetchedBlock = self.fetchedDetailRecord
        queryOp.resultsLimit = 5
        queryOp.queryCompletionBlock =  [weak self]
          (cursor: CKQueryCursor!, error: NSError!) -> Void in
          println("comp block called with \(cursor) \(error)")
          if error != nil 
            println("Error on fetch \(error.userInfo)")
           else 
            if cursor != nil 
              let nextOp = CKQueryOperation(cursor: cursor)
              nextOp.recordFetchedBlock = self!.fetchedDetailRecord
              nextOp.queryCompletionBlock = queryOp.queryCompletionBlock
              nextOp.resultsLimit = 5
              self!.publicDatabase?.addOperation(nextOp)
              println("added next fetch")
             else 
              self!.fileHandle!.closeFile()
              self!.exportProgressIndicator.stopAnimation(self)
            
          
        

        self.publicDatabase?.addOperation(queryOp)

这是来自控制台的结果 -

459013587628.012 0 459013587628.621 1 459013587628.863 2 459013587629.113 3 459013587629.339 4 用 nil 调用的 comp 块 添加了下一次提取 459013587828.552 5 459013587828.954 6 459013587829.198 7 459013587829.421 8 459013587829.611 9 用 nil 调用的 comp 块 添加了下一次提取 459013587997.084 10 459013587997.479 11 459013587997.74 12 459013587997.98 13 459013587998.207 14

大数字只是调用recordFetchedBlock之间的时间,第二个数字是调用该块的次数。

我很难过...关于如何继续的任何想法?哦,container和publicDatabase都是类变量,在运行上面的sn-p代码之前进行了初始化。

【问题讨论】:

【参考方案1】:

您在 queryCompletionBlock 范围内定义 nextOp 的方式在该块的三次迭代后会导致问题。如果您将 CKQueryOperation 的创建分解为它自己的方法,您的问题就会消失。

代码如下:

func fetchedDetailRecord(record: CKRecord!) -> Void 
    println("Retrieved record: \(record)")


func createQueryOperation(cursor: CKQueryCursor? = nil) -> CKQueryOperation 
    var operation:CKQueryOperation
    if (cursor != nil) 
        operation = CKQueryOperation(cursor: cursor!)
     else 
        operation = CKQueryOperation(query: CKQuery(...))
    
    operation.recordFetchedBlock = self.fetchedDetailRecord
    operation.resultsLimit = 5
    operation.queryCompletionBlock =  [weak self]
        (cursor: CKQueryCursor!, error: NSError!) -> Void in
        println("comp block called with \(cursor) \(error)")
        if error != nil 
            println("Error on fetch \(error.userInfo)")
         else 
            if cursor != nil 
                self!.publicDatabase?.addOperation(self!.createQueryOperation(cursor: cursor))
                println("added next fetch")
             else 
                self!.fileHandle!.closeFile()
                self!.exportProgressIndicator.stopAnimation(self) 
            
        
    
    return operation


func doQuery() 
    println("Querying records...")
    self.publicDatabase?.addOperation(createQueryOperation())

【讨论】:

感谢 Dave,很抱歉花了这么长时间才回复,但您的回复已经结束。一旦我将它移到它自己的函数中,查询就会完美运行。 谢谢!但是,似乎 operation.cursor = cursor 并没有使操作以光标开始;而是使用 operation = CKQueryOperation(cursor: cursor) 为我工作 - 想法? 啊,很好。文档确实说“当您使用游标时,查询属性的内容将被忽略”,因此我相应地更新了代码示例。 这个解决方案有一个主要缺点,但是:初始操作将在所有子操作完成之前结束。因此,我们不能将它用于操作之间的依赖关系:-( 我尝试使用 addOperations(:waitUntilFinished) 而不是 addOperation() 但是......它在三次迭代后停止。有什么想法吗?【参考方案2】:

这可能是另一种方法(已经更新到 Swift 3)。

第三次迭代后不会停止,而是一直持续到结束

var queryOp = CKQueryOperation(query: query)
queryOp.recordFetchedBlock = self.fetchedARecord
queryOp.resultsLimit = 5
queryOp.queryCompletionBlock =  [weak self] (cursor : CKQueryCursor?, error : Error?) -> Void in
    print("comp block called with \(cursor) \(error)")

    if cursor != nil 
        let nextOp = CKQueryOperation(cursor: cursor!)
        nextOp.recordFetchedBlock = self!.fetchedARecord
        nextOp.queryCompletionBlock = queryOp.queryCompletionBlock
        nextOp.resultsLimit = queryOp.resultsLimit

        //this is VERY important
        queryOp = nextOp

        self!.publicDB.add(queryOp)
        print("added next fetch")
    



self.publicDB.add(queryOp)

我成功地用它从 CloudKit 中检索了数百条记录

【讨论】:

我遇到了同样的问题,您的评论“这非常重要”解决了这个问题。我要补充的是你强调它的重要性的那一行。你让我今天一整天都感觉很好。谢谢!

以上是关于CKQueryOperation queryCompletionBlock 只运行 3 次的主要内容,如果未能解决你的问题,请参考以下文章

使用 CKQueryOperation 和 CKReference 获取大集合

CKQueryOperation 处理大批量

CloudKit:删除记录的 CKQueryOperation

CloudKit - 具有依赖关系的 CKQueryOperation

CKQueryOperation queryCompletionBlock 返回一个 nil 游标

CKQueryOperation resultLimit max 和 request count