0

I've tried to understand this by reading: https://developer.apple.com/library/ios/documentation/Performance/Reference/GCD_libdispatch_Ref/

But it is soooooo confusing. I know that the following code has to do something with queueing the task. I think that queueing means waiting? And I'm not sure what the task is. And I know that it somehow speeds up the execution of the code that is inside this code. Still, I'm very confused when it is used and why it is used.

dispatch_async(dispatch_get_main_queue(), { () -> Void in    
})

The above code is found in this body of code:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var cityTextField: UITextField!
@IBOutlet weak var resultLabel: UILabel!
@IBAction func findWeather(sender: AnyObject) {
    let url = NSURL(string: "http://www.weather-forecast.com/locations/Riverside/forecasts/latest")!
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in
        if let urlContent = data {
            let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)

            var websiteArray = webContent!.componentsSeparatedByString("3 Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
            let tempText = websiteArray[1]

            websiteArray = tempText.componentsSeparatedByString("</span></span></span></p><div class=\"forecast-cont\"><div class=\"units-cont\"><a class=\"units metric active\">&deg;C</a><a class=\"units imperial\">&deg;")
            print(websiteArray[0])
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.resultLabel.text = websiteArray[0]
            })

        }
    }
    task?.resume()
}
rmaddy
  • 314,917
  • 42
  • 532
  • 579
aejhyun
  • 612
  • 1
  • 6
  • 19

2 Answers2

3

in short, the code inside the dispatch_async block will execute asynchronously on a queue(thread) of your choosing (main queue is the UI thread)

why it speeds up your code is, because self.resultLabel.text = websiteArray[0] not being inside a block that would run on the main thread would make the code execute on a different thread that is not the UI thread (since the NSURLSession completion handler happens on a different thread), and updating the UI not on the UI thread causes strange behaviour (mainly just random delays in updating the UI)

if you changed dispatch_get_main_queue() to a different queue, you would see the exact same behaviour as not having the block at all

maybe this will help clarify what line of code executes on what thread:

@IBAction func findWeather(sender: AnyObject) { //function called from UI thread
    let url = NSURL(string: "http://www.weather-forecast.com/locations/Riverside/forecasts/latest")! //UI thread
    let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) -> Void in //UI thread, but this function call now creates its own thread that the block will run on
//Not UI Thread ----------------------------
        if let urlContent = data {  
            let webContent = NSString(data: urlContent, encoding: NSUTF8StringEncoding)

            var websiteArray = webContent!.componentsSeparatedByString("3 Day Weather Forecast Summary:</b><span class=\"read-more-small\"><span class=\"read-more-content\"> <span class=\"phrase\">")
            let tempText = websiteArray[1]

            websiteArray = tempText.componentsSeparatedByString("</span></span></span></p><div class=\"forecast-cont\"><div class=\"units-cont\"><a class=\"units metric active\">&deg;C</a><a class=\"units imperial\">&deg;")
            print(websiteArray[0])
// -----------------------------------------
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                self.resultLabel.text = websiteArray[0] //UI thread
            })
//Not UI Thread again, if there was code here
        }
    }
    task?.resume() //inside the original function, so its on the UI thread
}
Fonix
  • 11,447
  • 3
  • 45
  • 74
  • Thank you for your response. I understand the word "Asynchronously" but I'm not sure what you mean by "on a queue(thread) of your choosing (main queue is the UI thread). What is a thread? And what does queue actually mean? – aejhyun Aug 13 '15 at 04:46
  • 1
    heh, seems like you need to go through the basics a bit. a queue and a thread are basically the same thing, just different terminology (there are some differences though you dont need to worry about), but basically, when a program starts, the OS launches a process, which is your app, the app can have multiple threads which are like having mini apps inside your app that all run at the same time (hence why multicore CPU's are useful, for running multiple threads concurrently). the threads just execute code like normal, but concurrently to other threads. – Fonix Aug 13 '15 at 04:51
  • 1
    so when you launch an NSURLSession, it happens on another thread, so your main UI thread doesnt get blocked and have to wait for your webservice to return before carrying on. so it instead launches another thread to do the waiting on, and then you need to make it update your ui back on the main thread, and not this new thread that it did its waiting on – Fonix Aug 13 '15 at 04:53
  • [this answer](http://stackoverflow.com/a/2987445/1219956) may clarify things further – Fonix Aug 13 '15 at 04:56
  • Okay. So I might have gotten it. Please tell me if I have the correct understanding. When the app launches, the main UI thread launches and when it "sees" the line of code containing NSURLSession thread, it launches another thread to get the data from the internet so that the main UI thread doesn't have to wait. Now, without the async block, the `self.resultLabel.text = websiteArray[0]` waits until the NSURLSession thread ends. But without the async block, the `self.resultLabel.text = websiteArray[0]` executes right when the necessary data is fetched? – aejhyun Aug 13 '15 at 05:02
  • 1
    yep, almost... without the block, it does wait till the NSURLSession ends, but more importantly, it runs that line of code on the same thread as the NSURLSession, which is not the main thread where all UI updates must happen. so introducing the block that runs back on the main thread, makes the code happen after the URLSession ends, but then back on the UI thread so the UI updates properly... unless thats what you meant, then you are correct – Fonix Aug 13 '15 at 05:11
  • I understand the first part, that is, they run the same thread while NSURLSession is the main thread. I'm sorry for asking so many questions... Gosh... So having the async block of code causes two threads to launch. And the block code executes after the URLSession ends, and then what happens? I'm sorry I'm still quite confused. And I tried to read the link that you've sent me and I was confused by so many terminologies that I didn't know. Is there another resource you can point me to? – aejhyun Aug 13 '15 at 05:37
  • 1
    dont have any resources im afraid, but google is your friend. But to clarify further, inside the `dataTaskWithURL` function, behind the scenes it is effectively calling its own dispatch_async block but not with `dispatch_get_main_queue()` and inside its own block, once its finished retrieving from the internet, it calls the block that you have defined in your code on that same thread, which is why doing UI updates in there doesnt work so well, so in your (NSURLSession) block, you are creating you own block to run back on the ui thread so the ui updates properly. – Fonix Aug 13 '15 at 05:50
  • 1
    think of it like train tracks, each track is a thread. you start with one track (the UI track), then when you call your NSURLSession, its splits the track into 2, then a URLSession train can wait there, while the UI trains can pass it on the original UI track. When the URLSession train gets going again, its moves along its own track for a bit doing processing, but now when it needs to update the UI, it cant do that on its own track, so has to merge back onto the UI track which is what that dispatch_async block lets you do – Fonix Aug 13 '15 at 05:53
0
dispatch_async(dispatch_get_main_queue(), { () -> Void in    
                self.resultLabel.text = websiteArray[0]
})

The above function is used to make the update on main thread, Any UI update related operation should be done on main thread & Because of that dispatch_get_main_queue() is passed as parameter.

If you remove this block & try to set the result value text without it then it may not update the UI OR will take time to update it.

Try to set different queue to make everything more clear to you.

Nilesh Patel
  • 6,318
  • 1
  • 26
  • 40