iOS: tableView.reloadData() doesn't work in swift

Florentin picture Florentin · Nov 26, 2014 · Viewed 15.1k times · Source

I'm trying to reload my table view after updating data in Swift but it doesn't seems to work. When I change tab and go back the table view is reloaded but not automatically. Here is my code:

override func viewDidLoad() {
    super.viewDidLoad()

    // some code

    refresh(self)
}

func refresh(sender: AnyObject) {
    // Reload the data

    self.tableView.reloadData()
}

I don't understand why it works in Objective-C but not in Swift... I also tried to put :

dispatch_async(dispatch_get_main_queue(), { () -> Void in
    self.tableView.reloadData()
})

because I saw this in other post but it doesn't work either.

Thanks for helping

EDIT: My whole View Controller

class HighwaysViewController: UITableViewController {

    var highways: [Highway]!

    override func viewDidLoad() {
        super.viewDidLoad()

        // 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()

        highways = [Highway]()

        // On ajoute le "Pull to refresh"
        refreshControl = UIRefreshControl()
        refreshControl!.addTarget(self, action: Selector("refresh:"), forControlEvents: UIControlEvents.ValueChanged)
        tableView.addSubview(refreshControl!)

        refresh(self)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func refresh(sender: AnyObject) {
        // Afficher l'icône de chargement dans la barre de status
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true

        // On télécharge les autoroutes
        var url = NSURL(string: "http://theurl.com")! // URL du JSON
        var request = NSURLRequest(URL: url) // Création de la requête HTTP
        var queue = NSOperationQueue()  // Création de NSOperationQueue à laquelle le bloc du gestionnaire est distribué lorsque la demande complète ou échoué

        // Envoi de la requête asynchrone en utilisant NSURLConnection
        NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{(response: NSURLResponse!, data: NSData!, error: NSError!) ->Void in
            // Gestion des erreurs de connexion
            if error != nil {
                // Masquer l'icône de chargement dans la barre de status
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false

                println(error.localizedDescription)
                let errorAlert = UIAlertView(title: "Erreur", message: error.localizedDescription, delegate: self, cancelButtonTitle: "OK")
                errorAlert.show()
            }
            else {
                // Récupération du JSON et gestion des erreurs
                let json = JSON(data: data)

                if let highwaysData = json.arrayValue {
                    for highway in highwaysData {
                        var newHighway = Highway(ids: highway["Ids"].stringValue, name: highway["Name"].stringValue, label: highway["Direction"].stringValue, length: highway["Length"].stringValue, directions: highway["Direction"].stringValue, operateur: highway["Operator"].stringValue)
                        self.highways.append(newHighway)
                    }
                }
            }
        })

        if (self.refreshControl!.refreshing) {
            self.refreshControl!.endRefreshing()
        }

        tableView.reloadData() // Here is the problem

        // Masquer l'icône de chargement dans la barre de status
        UIApplication.sharedApplication().networkActivityIndicatorVisible = false
    }

    // MARK: - Table view data source

    override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // Return the number of rows in the section.
        return highways.count
    }

    override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCellWithIdentifier("highwayCell", forIndexPath: indexPath) as UITableViewCell

        // Configure the cell...
        let tableCell = highways[indexPath.row]

        let nameLabel = cell.viewWithTag(1) as UILabel
        let directionLabel = cell.viewWithTag(2) as UILabel

        nameLabel.text = tableCell.name!
        directionLabel.text = tableCell.getDirections()

        return cell
    }

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        // Get the new view controller using [segue destinationViewController].
        // Pass the selected object to the new view controller.
    }
    */

}

Answer

Paulw11 picture Paulw11 · Nov 26, 2014

In your refresh function, your load completes asynchronously using a closure, but you are updating your activity indicator and reloading your table outside of the closure, so it will execute before the load is completed. You need to move this code inside the closure and ensure that it executes on the main queue (as it updates the UI)

func refresh(sender: AnyObject) {
        // Afficher l'icône de chargement dans la barre de status
        UIApplication.sharedApplication().networkActivityIndicatorVisible = true

        // On télécharge les autoroutes
        var url = NSURL(string: "http://theurl.com")! // URL du JSON
        var request = NSURLRequest(URL: url) // Création de la requête HTTP
        var queue = NSOperationQueue()  // Création de NSOperationQueue à laquelle le bloc du gestionnaire est distribué lorsque la demande complète ou échoué

        // Envoi de la requête asynchrone en utilisant NSURLConnection
        NSURLConnection.sendAsynchronousRequest(request, queue: queue, completionHandler:{(response: NSURLResponse!, data: NSData!, error: NSError!) ->Void in
            // Gestion des erreurs de connexion
            if error != nil {
                // Masquer l'icône de chargement dans la barre de status
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false

                println(error.localizedDescription)
                let errorAlert = UIAlertView(title: "Erreur", message: error.localizedDescription, delegate: self, cancelButtonTitle: "OK")
                errorAlert.show()
            }
            else {
                // Récupération du JSON et gestion des erreurs
                let json = JSON(data: data)

                if let highwaysData = json.arrayValue {
                    for highway in highwaysData {
                        var newHighway = Highway(ids: highway["Ids"].stringValue, name: highway["Name"].stringValue, label: highway["Direction"].stringValue, length: highway["Length"].stringValue, directions: highway["Direction"].stringValue, operateur: highway["Operator"].stringValue)
                        self.highways.append(newHighway)
                    }
                }
            }

            dispatch_async(dispatch_get_main_queue(), {

                if (self.refreshControl!.refreshing) {
                    self.refreshControl!.endRefreshing()
                }

                self.tableView.reloadData() 

                // Masquer l'icône de chargement dans la barre de status
                UIApplication.sharedApplication().networkActivityIndicatorVisible = false
            })

        })

    }