37

I believe I'm having an issue where my closure is happening on a background thread and my UITableView isn't updating fast enough. I am making a call to a REST service and in my closure i have a tableView.reloadData() call but it takes a few seconds for this to happen. How do I make the data reload faster (perhaps on the main thread?)

REST Query Function - using SwiftyJSON library for Decoding

func asyncFlightsQuery() {
    var url : String = "http://127.0.0.1:5000/flights"
    var request : NSMutableURLRequest = NSMutableURLRequest()
    request.URL = NSURL(string: url)
    request.HTTPMethod = "GET"

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse!, networkData: NSData!, error: NSError!) -> Void in
        var error: AutoreleasingUnsafeMutablePointer<NSError?> = nil


        // Parse with SwiftyJSON
        let json = JSON(data: networkData)

        // Empty out Results array
        self.resultArray = []

        // Populate Results Array
        for (key: String, subJson: JSON) in json["flights"] {
            print ("KEY: \(key) ")
            print (subJson["flightId"])
            print ("\n")

            self.resultArray.append(subJson)
        }

        print ("Calling reloadData on table..??")
        self.tableView.reloadData()


    })
}

Once self.tableView.reloadData() is called in my debugger

Shruti Thombre
  • 1,009
  • 3
  • 11
  • 27
Jeef
  • 25,082
  • 16
  • 71
  • 136

6 Answers6

101

UIKit isn't thread safe. The UI should only be updated from main thread:

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

Update. In Swift 3 and later use:

DispatchQueue.main.async {
    self.tableView.reloadData()
}
Kirsteins
  • 25,621
  • 8
  • 72
  • 75
  • 1
    Correct code should be: dispatch_async(dispatch_get_main_queue(), {self.tableView.reloadData()}) – Jeef Oct 09 '14 at 12:16
  • Sorry about that, fixed. – Kirsteins Oct 09 '14 at 12:18
  • 2
    Shall we not use [weak self] instead of self to avoid retain cycles? – G.Abhisek Sep 02 '16 at 14:55
  • 2
    @G.Abhisek not required as the dispatch_async will never capture the block that captures strong self. – Kirsteins Sep 02 '16 at 18:32
  • Can you please explain a bit more clearly with respect to the context ? – G.Abhisek Sep 06 '16 at 12:44
  • 1
    @G.Abhisek `dispatch_async` will only hold the block that retains `self` only till the block is executed. Also the code that calls `dispatch_async` do not hold any reference to its internals, so there are no risk of retain cycles. – Kirsteins Sep 06 '16 at 12:47
  • @Kirsteins everywhere it is written that the UI should be updated from the main thread using dispatchQueue only but can you please explain as in why should it be like that. – Nishad Arora Apr 27 '18 at 04:27
4

You can also reload UITableView like this

self.tblMainTable.performSelectorOnMainThread(Selector("reloadData"), withObject: nil, waitUntilDone: true)
Anand Suthar
  • 1
  • 2
  • 24
  • 45
3

With Swift 3 use

DispatchQueue.main.async {
    self.tableView.reloadData()
}
Sal
  • 1,190
  • 11
  • 21
2

You can also update the main thread using NSOperationQueue.mainQueue(). For multithreading, NSOperationQueue is a great tool.

One way it could be written:

NSOperationQueue.mainQueue().addOperationWithBlock({
     self.tableView.reloadData()       
})

Update: DispatchQueue is the way to go for this

Update 2: Use DispatchQueue solution as seen in accepted answer above

bubbaspike
  • 81
  • 6
1

SWIFT 3:

OperationQueue.main.addOperation ({
     self.tableView.reloadData()
})
Maksim Kniazev
  • 3,589
  • 26
  • 34
1
DispatchQueue.main.async {
    self.tableView.reloadData()
}

Do this to update the UI on the main thread. Using this method it will bring update the table view and reflect the data in the UI.

SudhakarH
  • 181
  • 1
  • 9