swiftpaginationcloudkitckqueryoperation

batch fetching with cloudkit ckqueryoperation


Is it possible to implement 'batch fetching' in cloudkit, so that i can call a method to pull the next X records? Currently, according to CloudKit Batch Fetches? cloudkit handles this implicitly, but I would like to somehow create a method that allows me to pull a specified number of queries each time. Heres what I have so far: (where continuePullPosts is a similar method to the one i posted)

queryOP.recordFetchedBlock = { record in
        //do stuff here
        annotations.append(postToAdd)
    }

    queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
        DispatchQueue.main.async {
            if error == nil {
                if completionHandler(annotations) {
                    if cursor != nil {
                        let newQueryOP = CKQueryOperation(cursor: cursor!)
                        self.continuePullPosts(curLocation: curLocation, queryOP: newQueryOP,
                                               annotations: annotations, completionHandler: completionHandler)
                    }
                }
            } else {
                print(error)
                print("could not pull posts")
            }
        }
    }

    queryOP.resultsLimit = CKQueryOperationMaximumResults
    CKContainer.default().publicCloudDatabase.add(queryOP)
}

Solution

  • You should set the result limit with your desired value instead of CKQueryOperationMaximumResultsconstant value.

    My recomendation is define a completion handler with parameters for the CKRecord results and the CKQueryCursor. This completion handler must be invoked in the queryCompletionBlock handler of your CKQueryOperation.

    Once your handler is invoked you can process the results, and if the cursor is not null means that there are more results to fetch.

    It could be something like that

    // Completion Handler (closure) definition
    public typealias YourFetchCompletionHandler = (_ records: [CKRecords]?, cursor: CKQueryCursor?) -> (Void)
    

    And here the function where you fetch records

    public func fetchYourRecords(_ cursor: CKQueryCursor? = nil, completionHandler handler: @escaping YourFetchCompletionHandler) -> Void
    {
        var result: [CKRecord] = [CKRecord]()
    
        let queryOP: CKQueryOperation
    
        if let cursor = cursor
        {
            // Operation to fetch another 10 records.
            queryOP = CKQueryOperation(cursor: cursor)
        }
        else
        {
            // Create the operation for the first time
            queryOP = CKQueryCursor(query:...)
        }
    
        queryOp.recordFetchedBlock = { (record: CKRecord) -> Void in
            result.append(record)
        }
    
        queryOP.queryCompletionBlock = { [unowned self] (cursor, error) in
            handler(result, cursor)    
        }
    
        // Fetch only 10 records
        queryOP.resultsLimit = 10
        CKContainer.default().publicCloudDatabase.add(queryOP)
    }
    

    Once you invoke this function you can save the cursor returned in the closure in a variable, if it's not nil, to call once again the function to recover the next 10 records.