Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CKQuery from private zone returns only first 100 CKRecords from in CloudKit

Is there any limit to the result of a query to Cloudkit private default zone? I have no clue why I only receive first 100 records with the following query:

let p = NSPredicate(format: "(type == 'entered') AND (timestamp >= %@) AND (timestamp <= %@)", from, to)
let q = CKQuery(recordType: self.beaconRecordType, predicate: p)
q.sortDescriptors = [NSSortDescriptor(key: "timestamp", ascending: true)]
self.privateDatabase?.performQuery(q, inZoneWithID: nil, completionHandler: { results, error in

    //count = 100
    println(results.count)

}

Okay. As Edwin mention in the answer, the solution is to use CKQueryOperation to fetch the initial block of data then use the "cursor" in completionBlock to fire another operation. Here is an example:

UPDATE

func fetchBeacons(from:NSDate, to:NSDate) {

    let p = NSPredicate(value: true)
    let q = CKQuery(recordType: self.beaconRecordType, predicate: p)

    let queryOperation = CKQueryOperation(query: q)

    queryOperation.recordFetchedBlock = fetchedARecord

    queryOperation.queryCompletionBlock = { [weak self] (cursor : CKQueryCursor!, error : NSError!) in

        if cursor != nil {
            println("there is more data to fetch")
            let newOperation = CKQueryOperation(cursor: cursor)
            newOperation.recordFetchedBlock = self!.fetchedARecord
            newOperation.queryCompletionBlock = queryOperation.queryCompletionBlock
            self!.privateDatabase?.addOperation(newOperation)
        }

    }

    privateDatabase?.addOperation(queryOperation)
}

var i = 0
func fetchedARecord (record: CKRecord!) {
    println("\(NSDate().timeIntervalSinceReferenceDate*1000) \(++i)")
}
like image 929
CppChase Avatar asked Apr 12 '15 18:04

CppChase


1 Answers

I have updated GuiSoySauce's code in Swift 4.2.

func cloudKitLoadRecords(result: @escaping (_ objects: [CKRecord]?, _ error: Error?) -> Void) {
    // predicate
    var predicate = NSPredicate(value: true)
    // query
    let cloudKitQuery = CKQuery(recordType: "recordType", predicate: predicate)

    // records to store
    var records = [CKRecord]()

    //operation basis
    let publicDatabase = CKContainer.defaultContainer().publicCloudDatabase

    // recurrent operations function
    var recurrentOperationsCounter = 101
    func recurrentOperations(cursor: CKQueryCursor?){
        let recurrentOperation = CKQueryOperation(cursor: cursor!)
        recurrentOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
            print("-> cloudKitLoadRecords - recurrentOperations - fetch \(recurrentOperationsCounter)")
            recurrentOperationsCounter += 1
            records.append(record)
        }
        recurrentOperation.queryCompletionBlock = { (cursor: CKQueryOperation.Cursor?, error: Error?) -> Void in
            if ((error) != nil) {
                print("-> cloudKitLoadRecords - recurrentOperations - error - \(String(describing: error))")
                result(nil, error)
            } else {
                if cursor != nil {
                    print("-> cloudKitLoadRecords - recurrentOperations - records \(records.count) - cursor \(cursor!.description)")
                    recurrentOperations(cursor: cursor!)
                } else {
                    print("-> cloudKitLoadRecords - recurrentOperations - records \(records.count) - cursor nil - done")
                    result(records, nil)
                }
            }
        }
        publicDatabase.add(recurrentOperation)
    }
    // initial operation
    var initialOperationCounter = 1
    let initialOperation = CKQueryOperation(query: cloudKitQuery)
    initialOperation.recordFetchedBlock = { (record:CKRecord!) -> Void in
        print("-> cloudKitLoadRecords - initialOperation - fetch \(initialOperationCounter)")
        initialOperationCounter += 1
        records.append(record)
    }
    initialOperation.queryCompletionBlock = { (cursor: CKQueryOperation.Cursor?, error: Error?) -> Void in
        if ((error) != nil) {
            print("-> cloudKitLoadRecords - initialOperation - error - \(String(describing: error))")
            result(nil, error)
        } else {
            if cursor != nil {
                print("-> cloudKitLoadRecords - initialOperation - records \(records.count) - cursor \(cursor!.description)")
                recurrentOperations(cursor: cursor!)
            } else {
                print("-> cloudKitLoadRecords - initialOperation - records \(records.count) - cursor nil - done")
                result(records, nil)
            }
        }
    }
    publicDatabase.add(initialOperation)
}

Usage

cloudKitLoadRecords() { (records, error) -> Void in
    if let error = error {
        // do something
    } else {
        if let records = records {
            // do something
        } else {
            // do something
        }
    }
}
like image 148
HirofumiYamamoto Avatar answered Sep 29 '22 14:09

HirofumiYamamoto