32

I have seen this code snippet:

dispatch_async(dispatch_get_main_queue(), ^{
    [self doSomeNetworkStuff];
});

This doesn't look like making much sense to me.

EDIT: To clarify the conditions of my question:

  • The call to dispatch_async is performed from the main thread.
  • The sent message doSomeNetworkStuff is the heavy lifting worker task.
  • ... and is not only the UI-updating task.

Dispatch, sure, but using the main queue would just pull the dispatched task back to the ui thread and block it.

Please, am I missing something? Thanks.

nine stones
  • 3,264
  • 1
  • 24
  • 36
  • 5
    You missed the difference between `dispatch_sync` and `dispatch_async`, where the latter one does put the function in the main queue but it does not wait for the function to complete before returning. That's why it's **async**. – He Shiming Mar 02 '13 at 02:17
  • I see that. However, if `doSomeNetworkStuff` was executed at end of the current run loop, then the advantage is basically voided, right? – nine stones Mar 02 '13 at 12:57
  • Well, you see, certain stuff (such as UI related) has to be executed in the so called UI thread (which is the main thread). `dispatch_async` allows such stuff to be executed in the queue, rather than right away. Basically the UI becomes more responsive this way. – He Shiming Mar 02 '13 at 14:33

6 Answers6

38

dispatch_async lets your app run tasks on many queues, so you can increase performance. But everything that interacts with the UI must be run on the main thread. You can run other tasks that don't relate to the UI outside the main thread to increase performance.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{

  //Add some method process in global queue - normal for data processing

    dispatch_async(dispatch_get_main_queue(), ^(){
    //Add method, task you want perform on mainQueue
    //Control UIView, IBOutlet all here

    });

 //Add some method process in global queue - normal for data processing

});
gavdotnet
  • 2,214
  • 1
  • 20
  • 30
Alex
  • 1,161
  • 1
  • 8
  • 15
  • 18
    This is a good answer, but do not assume that putting things on another thread increases total speed. It may, if well designed and profiled. It can also be slower if done incorrectly or not profiled, sometimes dramatically slower if you create too many blocks. On an original iPad, which only has one core, threads can never improve total speed (by necessity, multiple threads will be slower in total since it adds context switches). The primary reason for moving things onto other queues is to improve UI responsiveness, not actual speed (particularly on low-core devices like iPhones and iPads). – Rob Napier Mar 02 '13 at 03:45
  • @Ios10: I've edited my question to clarify, that the call to `dispatch_async` takes place at the end of the current run loop (thus, on the UI thread). And to clarify that `[doSomeNetworkStuff]` is not the UI updating task, but the worker task that uses network resources. – nine stones Mar 02 '13 at 13:06
  • Any job can be on main queue, but UI update can not outside.Try to put your netWork task in global queue and check performance. – Alex Mar 03 '13 at 03:18
8

Swift 3:

DispatchQueue.global(attributes: .qosBackground).async {
    print("This is run on the background queue")

    DispatchQueue.main.async {
        print("This is run on the main queue, after the previous code in outer block")
    }
}
Alessandro Ornano
  • 34,887
  • 11
  • 106
  • 133
6

when you want to do some Webservicecall or something you dispatch a async call like this below:

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
        //Call your webservice here , your app will not freeze at all  
});

Now, suppose you want to update or push a ViewController from your dispatched thread, if you directly push viewcontroller from this, app will or may get crashed,as such UI updates should be done in main thread of app,below is the answer for this then.

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0),^{
       //Call your webservice here , your app will not freeze at all

       //To update UIFrom dispatched Thread:

       dispatch_async(dispatch_get_main_queue,^{   

       //Push view controller here
});

});

for detail visit : blackberrymastercracks.blogspot.in

Dirty-flow
  • 2,306
  • 11
  • 30
  • 49
user1826351
  • 91
  • 1
  • 1
  • 2
    I'd recommend against using GCD for webservice calls as you have no ability to cancel the underlying NSURLConnection. Once a block is executed to GCD, you have no way of cancelling. Use NSOperation or a third party framework such as MKNetworkKit / AFNetworking. – Fergal Rooney Apr 02 '14 at 14:58
5

It depends from where this code is being called. Means if its calling from main queue then it doesn't make sense. (Note: it will not cause a crash but it will just add a task in main queue ).

If this code is written in background thread then this is a converging point for the application. Like you are getting data from web service in background thread then wants to update it on UI then you can call it.

-(void) backgroundThreadFunction {

     //Some stuff on background thread. 

     dispatch_async(dispatch_get_main_queue(), ^{
         //Wants to update UI or perform any task on main thread.    
         [self doSomeNetworkStuff];
     });
}

You can find more details over apple documentation https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues/OperationQueues.html or from this answer also https://stackoverflow.com/a/19822753/505735

Do post me if its still unclear. I will write a detailed answer.

Community
  • 1
  • 1
3

You'll usually see that syntax inside of another dispatch_async call that runs on a background thread. This is because all updates to the UI should happen on the main thread, not in the background.

Richard Brown
  • 11,346
  • 4
  • 32
  • 43
0

I lost track of this question, but as it still gets traction, I'll post an answer to this (using swift)

Assumptions: I do know that UI work has to be done on the main thread.

//
// We are on the main thread here.
// The following will schedule the closure on the main thread after ALL other 
//   routines currently scheduled on the main thread are done. 
//
DispatchQueue.main.async {
    //
    // So here we are back on the main thread AFTER all routines on the main 
    //   thread have completed.
    // 
    // If the following call does NOT dispatch onto a background thread 
    //    it will block the UI and it was really bad programming.
    // 
    // Thus, for now and for the benefit of the doubt, let's assume 
    //   `doSomeNetworkStuff()` DOES dispatch to a background thread.
    //   
    // This can only make sense if the the func `doSomeNetworkStuff()` 
    //   relies on results of code paths following this current 
    //   `DispatchQueue.main.async(... we are here ...)`.
    //
    // If `doSomeNetworkStuff()` does NOT depend on any other code paths:
    //   Why not directly scheduling it directly on a background thread? 
    //   Which is unnecessary, as as stated above it MUST dispatch on to the
    //     background anyways.
    // 
    // Moreover, there is few possibility that `doSomeNetworkStuff()` does 
    //   depend on other codepaths, because `self` is already captured by 
    //   the closure.
    //
    self.doSomeNetworkStuff()
}

Taking all this together IMHO the original code does not make very much sense. It could be replaced with:

// We are on the main thread here
self.doSomeNetworkStuff()

The original async dispatch onto the main thread to then dispatch to background should be wasteful and confusing (obviously).

Unfortunately I am not in the position anymore to try this out with the original code base.

Am I missing an idea here?

nine stones
  • 3,264
  • 1
  • 24
  • 36
  • 1
    I can think of one contrived example: suppose we know an `NSLock` has been acquired outside on the main thread before the `async` call. For whatever reason, `doSomeNetworkStuff()` also acquires the same lock (on whatever thread its called on). In that case, calling `doSomeNetworkStuff()` directly would deadlock, but dispatching it back to the main thread will work. – p00ya Sep 08 '20 at 07:15