swiftcloudkitckquery

Executing a CKQueryOperation multiple times with a new cursor


I have a CKQueryOperation working with a thousand of records thus I need to do the operation multiple times. I tried to change the cursor and add the operation like in this code:

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)

When running it crashes and returns [NSOperationQueue addOperation:]: operation is executing and cannot be enqueued. What could I do? I have other operations after that that are dependent on this queryOperation so I need to finis hit properly before starting other CKOperations.


Solution

  • Instead of executing the same operation an other time, you should create a new one. Below you can see a code snippet from EVCloudKitDao to see how it can be used.

    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)
    }