2

Reloading my table after the performQuery operation completes using CloudKit. The problem is reloading the table with data from the Cloud. My data is good, no problems there.

I found this thread which I think will solve it but I don’t know when to call it and how to call it.

Wait For Asynchronous Operation To Complete in Swift

-- Code

import UIKit
import CloudKit

class DownloadTableViewController: UITableViewController {

    var rooms: [String] = []
    var appliance: [String] = []
    let container = CKContainer.defaultContainer()
    var publicDatabase: CKDatabase?
    var currentRecord: CKRecord?
    let publicDB = CKContainer.defaultContainer().privateCloudDatabase


    var receivedString = myHouse.houseData

    override func viewDidLoad() {
        super.viewDidLoad()
        rooms.removeAll()
        appliance.removeAll()
        reloadMyData()
        //performQuery()
        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem()
    }
    override func viewDidAppear(animated: Bool) {
        rooms.removeAll()
        appliance.removeAll()
        reloadMyData()
        print("Calling query")
        performQuery()
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        print("Received memory warning")
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

    override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Incomplete implementation, return the number of sections
        return 1
    }

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        if rooms.count == 0 {
            return 1
        }
        else {
            return rooms.count
        }
    }


    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {

        let cell = tableView.dequeueReusableCellWithIdentifier("downloadTableCell", forIndexPath: indexPath)
            as! DownloadTableViewCell
        print(" rooms: \(rooms.count)")
        // Configure the cell...
        if rooms.count == 0 {
            cell.downloadLabel.text = "Waiting for Cloud Data....."
        }
        else {
            cell.downloadLabel.text = rooms[indexPath.row] + " - " + appliance[indexPath.row]
        }
        return cell
    }


    /*
    // Override to support conditional editing of the table view.
    override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    // Return false if you do not want the specified item to be editable.
    return true
    }
    */

    /*
    // Override to support editing the table view.
    override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
    // Delete the row from the data source
    tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    } else if editingStyle == .Insert {
    // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }
    }
    */

    /*
    // Override to support rearranging the table view.
    override func tableView(tableView: UITableView, moveRowAtIndexPath fromIndexPath: NSIndexPath, toIndexPath: NSIndexPath) {

    }

    func performQuery() {
        //let tempCloudID = "B16AEB76-AA36-491A-B3C7-775602466ECB"
        //application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!)
        // NOT SURE HOW TO CALL THE ABOVE LINE OR WHERE TO CALL IT
        let tempCloudID = myCurrentHouse[5]
        let predicate = NSPredicate(format: "CloudID = %@", tempCloudID)
        //let sort = NSSortDescriptor(key: "Room", ascending: true)

        let query = CKQuery(recordType: "ImagesSaved", predicate: predicate)
        query.sortDescriptors = [NSSortDescriptor(key: "Room", ascending: true)]
        publicDB.performQuery(query, inZoneWithID: nil , completionHandler: ({ results, error in
            if(error != nil) {
                dispatch_async(dispatch_get_main_queue()) {
                    self.notifyUser("Cloud Access Error", message: error!.localizedDescription)
                    print("Error")
                    self.rooms.removeAll()
                    self.appliance.removeAll()
                    self.rooms.append("Cloud Error")
                    self.appliance.append("Connected?")
                    //self.reloadMyData()


                }
            }
            else {
                if results!.count > 0 {
                    self.rooms.removeAll()
                    self.appliance.removeAll()
                    for record in results! {
                        self.rooms.append(record.objectForKey("Room") as! String)
                        self.appliance.append(record.objectForKey("Appliance") as! String)
                        print("I have results from query")
                    }
                    self.reloadMyData()
                }
                else {
                    print("query returned with no results")
                    self.rooms.removeAll()
                    self.appliance.removeAll()
                    self.rooms.append("No Data")
                    self.appliance.append(" ")
                    self.reloadMyData()

                }
            }
        }))
        //self.reloadMyData()
    }
    func notifyUser(title: String, message: String) -> Void {
        let alert = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
        let cancelAction = UIAlertAction(title: "OK", style: .Cancel, handler: nil)
        alert.addAction(cancelAction)
        self.presentViewController(alert, animated: true, completion: nil)
    }
    func reloadMyData() {
        print("Reloading data \(self.rooms.count)")
        self.tableView.reloadData()
    }
}
Community
  • 1
  • 1
Grumpy
  • 155
  • 10
  • What si your problem exactly? – Alexandre Barbier Jan 02 '16 at 19:40
  • When the page loads is makes a call to performQuery to get data, I need to update the table with the information from the cloud. I need to know when the performQuery has completed, and my data is ready, then update the table. I t seems like I could do that in the last line of performQuery, but that does not seem to work. The thread I have linked above might be a possible answer, but I don't know how to implement that in my code. – Grumpy Jan 02 '16 at 20:02
  • I am also getting this error when trying to re-load the data: This application is modifying the autolayout engine from a background thread, I am testing on 9.1. I believe it is because of the way that I am trying to re-load the data to the table. – Grumpy Jan 02 '16 at 20:06
  • Ok. It seems you try to reload your tablebleview from a background thread. You should use dispatch_async(dispatch_get_main_queue()) everywhere you call tablebleview.reloaddata – Alexandre Barbier Jan 03 '16 at 02:08
  • If I read your code correctly you already know when your query is complete : publicDB.performQuery(query, inZoneWithID: nil , completionHandler:{}). the completionHandler parameter is a block executed when your query is complete and you should reload your tableview in this block (you have to perform your reload in the main thread) – Alexandre Barbier Jan 04 '16 at 12:04
  • func performQuery() { publicDB.performQuery(query, inZoneWithID: nil , completionHandler: ({ results, error in if(error != nil) { dispatch_async(dispatch_get_main_queue()) { // do stuff } } else { if results!.count > 0 { //do more stuff } else { //do more stuff } } self.reloadMyData() // - Calls reload data here without any errors })) } – Grumpy Jan 04 '16 at 18:26
  • So just add a closure to performQuery like this func performQuery(completion:(your parameters) -> Void) { } – Alexandre Barbier Jan 04 '16 at 18:36
  • I have 4 pages that use the cloud for syncing, uploading and downloading. I need to start another project that uses the completion and get that figured out, then go back to the app and make changes. It still does not make sense to me although I have read the documentation. I don't understand completion(your parameters). I guess that I'd like to call a function there to update the table with the cloud data that was downloaded. More reading:) – Grumpy Jan 06 '16 at 18:58
  • Read the swift programming book (free on iBooks) there is everything you need to know about closure – Alexandre Barbier Jan 06 '16 at 19:00
  • dispatch_async(dispatch_get_main_queue(), { () -> Void in self.reloadMyData() }) // Ended up using this and finally got rid of my errors – Grumpy Jan 14 '16 at 03:38
  • As I told you in my second comment ^^ – Alexandre Barbier Jan 14 '16 at 06:06

0 Answers0