ultragranata15
ultragranata15

Reputation: 1

Swift - Get all records from Cloudkit Public Database

Hi i'm trying to fetch all records from my publicDB in cloudkit, and currently there are more of 2000 records. How can I fetch them all and put them in an array? I've tryed these two methods without success. Can you please help me?

1 Approach

    let predicate = NSPredicate(value: true)
    let query = CKQuery(recordType: "Position", predicate: predicate)
    query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

publicDB.perform(query, inZoneWith: nil) { (results, error) -> Void in            

        if error != nil {

            DispatchQueue.main.async(execute: {  () -> Void in
                self.delegate?.errorUpdating(error: error! as NSError)
                return
            })
        } else {
            self.positionArray.removeAll(keepingCapacity: true)

            for record in results! {

                let position = Position(record: record as CKRecord, database: self.publicDB)
                self.positionArray.append(position)

            }
        }

            DispatchQueue.main.async(execute: {  () -> Void in
               /* my elaboration with the complete result */
            })



    }

2 Approach

    let predicate = NSPredicate(value: true)   
    let query = CKQuery(recordType: "Position", predicate: predicate)

    query.sortDescriptors = [NSSortDescriptor(key: "creationDate", ascending: false)]

    let qop  = CKQueryOperation(query: query)

    qop.resultsLimit = 3000        
    qop.recordFetchedBlock = { (record: CKRecord) in
        let position = Position(record: record, database: self.publicDB)
        self.positionArray.append(position)
        print(self.positionArray.count)
    }

    qop.queryCompletionBlock = { (cursor: CKQueryOperation.Cursor?, error: Error?) in
        DispatchQueue.main.async(execute: {  () -> Void in
        if let cursor = cursor {

            print("entro")
            let newOperation = CKQueryOperation(cursor: cursor)

            newOperation.recordFetchedBlock = qop.recordFetchedBlock
            newOperation.queryCompletionBlock = qop.queryCompletionBlock
            self.publicDB.add(newOperation)
        }

        else if let error = error {
            print("Error:", error)
        }
            // No error and no cursor means the operation was successful
        else {
            print("Finished with records:", self.positionArray)
            if(!all){
                // my elaboration
            }
            else{
                // my elaboration
            }
        }
        })
    }

    self.publicDB.add(qop)

With the first approach I can fetch at most 100 records. With the second approach I can fetch at most 400 records. But i need to fill my array with the all over 2000 records, how can achieve the result?

Upvotes: 0

Views: 1313

Answers (2)

Jean Luiz
Jean Luiz

Reputation: 20

Plese, Try this one!

var Whistle = [CKRecord] ()

func loadWhistles(completionHandler: (() -> Void)?) {
    let pred = NSPredicate(value: true)
    let sort = NSSortDescriptor(key: nomeDaTabela, ascending: ordemDaTabela)
    let query = CKQuery(recordType: "Cliente", predicate: pred)
    query.sortDescriptors = [sort]        

    let operation = CKQueryOperation(query: query)
    operation.desiredKeys = ["Name"]
    operation.resultsLimit = 2000

    var newWhistles = Whistle

    operation.recordFetchedBlock = { record in
        newWhistles.append(record)

    }


    operation.queryCompletionBlock = { [unowned self] (cursor, error) in
        DispatchQueue.main.async {
            if error == nil {
                //ViewController.isDirty = false
                self.clienteRecords = newWhistles
                self.clientesTableView.reloadData()
            } else {
                let ac = UIAlertController(title: "Fetch failed", message: "There was a problem fetching the list of whistles; please try again: \(error!.localizedDescription)", preferredStyle: .alert)
                ac.addAction(UIAlertAction(title: "OK", style: .default))
                self.present(ac, animated: true)
            }
        }
    }


    PublicDatabase.add(operation)
    completionHandler?()

}

Upvotes: 1

Maxim Volgin
Maxim Volgin

Reputation: 4077

There is indeed a limit of 400 records per fetch operation, so you need to check CKQueryCursor value returned by query completion block, and if it is not nil start another operation with it CKQueryOperation(cursor: cursor).

So in principle your 2nd approach is correct. My guess is that your problem occurs due to threading issue, try removing DispatchQueue.main.async(execute: { () -> Void in.

P.S. Check out how it is done in RxCloudKit (which handles big fetches automatically), it definitely works for fetching 1000+ records - RecordFetcher.queryCompletionBlock(cursor: CKQueryCursor?, error: Error?)

Upvotes: 0

Related Questions