使用新游标多次执行 CKQueryOperation

Posted

技术标签:

【中文标题】使用新游标多次执行 CKQueryOperation【英文标题】:Executing a CKQueryOperation multiple times with a new cursor 【发布时间】:2015-08-24 19:02:34 【问题描述】:

我有一个CKQueryOperation 处理一千条记录,因此我需要多次执行该操作。我尝试更改光标并添加如下代码中的操作:

let queryOperation = CKQueryOperation(query: query)
queryOperation.recordFetchedBlock =  (rule: CKRecord) in
        print(rule)

queryOperation.database = publicDB
queryOperation.queryCompletionBlock =  (cursor : CKQueryCursor?, error : NSError?) in
    if error != nil 
       print(error?.localizedFailureReason)
     else 
         if cursor != nil  // The cursor is not nil thus we still have some records to download
            queryOperation.cursor = cursor
            queue.addOperation(queryOperation)
          else 
              print("Done")
         
    

// Creation of the dependent operation secondQueryOperation
queue.addOperations([queryOperation, secondQueryOperation], waitUntilFinished: true)

运行时崩溃并返回[NSOperationQueue addOperation:]: operation is executing and cannot be enqueued。我能做什么?之后我还有其他操作依赖于这个 queryOperation,所以我需要在启动其他 CKOperations 之前正确命中。

【问题讨论】:

如何初始化 secondQueryOperation ? 正常初始化一个NSQueryOperation 然后secondQueryOperation.addDependency(queryOperation) 【参考方案1】:

您应该创建一个新操作,而不是再次执行相同的操作。下面你可以看到来自EVCloudKitDao的代码sn-p,看看它是如何使用的。

internal func queryRecords<T:EVCloudKitDataObject>(type:T, query: CKQuery, completionHandler: (results: [T]) -> Bool, errorHandler:((error: NSError) -> Void)? = nil) 
    if !(query.sortDescriptors != nil) 
        query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]
    
    let operation = CKQueryOperation(query: query)
    var results = [T]()
    operation.recordFetchedBlock =  record in
        if let parsed = self.fromCKRecord(record) as? T  
            results.append(parsed)
        
    

    operation.queryCompletionBlock =  cursor, error in
        self.handleCallback(error, errorHandler: errorHandler, completionHandler: 
            if completionHandler(results: results) 
                if cursor != nil 
                    self.queryRecords(cursor!, continueWithResults: results, completionHandler: completionHandler, errorHandler: errorHandler)
                
            
        )
    
    operation.resultsLimit = CKQueryOperationMaximumResults;
    database.addOperation(operation)



private func queryRecords<T:EVCloudKitDataObject>(cursor: CKQueryCursor, continueWithResults:[T], completionHandler: (results: [T]) -> Bool, errorHandler:((error: NSError) -> Void)? = nil) 
    var results = continueWithResults
    let operation = CKQueryOperation(cursor: cursor)
    operation.recordFetchedBlock =  record in
        if let parsed = self.fromCKRecord(record) as? T  
            results.append(parsed)
        
    

    operation.queryCompletionBlock =  cursor, error in
        self.handleCallback(error, errorHandler: errorHandler, completionHandler: 
            if completionHandler(results: results) 
                if cursor != nil 
                    self.queryRecords(cursor!, continueWithResults: results, completionHandler: completionHandler, errorHandler: errorHandler)
                
            
        )
    
    operation.resultsLimit = CKQueryOperationMaximumResults;
    database.addOperation(operation)

【讨论】:

只是一个小建议,在用光标安排下一个操作之前检查!results.isEmpty是否。当resultsLimit 恰好小于记录数时,有时即使获取了所有记录,也会返回游标。我认为这是CloudKit 的错误,最好使用!results.isEmpty 进行检查,这样我们就不会无限期地继续查询

以上是关于使用新游标多次执行 CKQueryOperation的主要内容,如果未能解决你的问题,请参考以下文章

使用游标多次更新 pgsql

11g新特性之自适应游标共享(Adaptive Cursor Sharing)

Oracle 自适应游标

将游标中的数据合并为一个

如何强制优化器重用 sql 游标

何时使用 MySQLdb 关闭游标