47

Starting to learn about core data and dispatch_async. There is a block of code to get url of image from set of data and set it to model of core data like below

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
                NSString *urlString = [[[photoDictionary valueForKey:@"images"] objectAtIndex:0] valueForKey:@"url"];
                NSData *imageData = [NSData dataWithContentsOfURL:[NSURL URLWithString:urlString]];
                dispatch_async(dispatch_get_main_queue(), ^{
                    [photoModel setValue:imageData forKey:@"photoImageData"];

Can somebody explain to me why we use dispatch_get_global_queue for the outer dispatch_async and dispatch_get_main_queue for inner dispatch_async.

tranvutuan
  • 6,089
  • 8
  • 47
  • 83

5 Answers5

93

The dispatch_get_global_queue (DispatchQueue.global() in Swift) gets you a background queue upon which you can dispatch background tasks that are run asynchronously (i.e. won't block your user interface). And if you end up submitting multiple blocks to the global queues, these jobs can operate concurrently. If you have multiple blocks of code that you want to submit to a background queue that you must have run sequentially in the background (not often needed), you could create your own serial background queue and dispatch to that, but if concurrent background operations are acceptable, then availing yourself of dispatch_get_global_queue is convenient/efficient.

Be aware, though, that you're not allowed to perform user interface updates in the background queue, so the dispatch_async to the dispatch_get_main_queue (i.e. DispatchQueue.main.async { ... } in Swift) lets that background queue dispatch the user interface updates back to the main queue, once the main queue is available.

This is a very common programming pattern: Submit something to run in the background and when it needs to perform user updates, dispatch the update back to the main queue.

For more information, refer to the Concurrency Programming Guide.

Rob
  • 415,655
  • 72
  • 787
  • 1,044
  • 18
    One further note: blocking IO on the global queue is not recommended, since the thread limit for the global queue is surprisingly low (64 threads). Once all available threads are blocked on IO, *any work elsewhere in your program, including in system frameworks* that uses the global queue will stall. – Catfish_Man Oct 02 '12 at 16:52
  • 1
    The system should be protecting itself from this via various private mechanisms, but it has been an issue in the past. Even if everyone in the frameworks is doing the right thing, why have 64 threads? That's just wasteful. – Catfish_Man Oct 10 '12 at 21:19
  • I might rephrase that. It’s more general than “blocking IO”. It’s anything that might “wait”. But it’s only a practical concern if you have so many that you might exhaust the very limited number of GCD worker threads. See “Thread Explosion Causing Deadlock” discussion in WWDC [2015 video](https://developer.apple.com/videos/play/wwdc2015/718/?time=2020) or the [2016 video](https://developer.apple.com/videos/play/wwdc2016/720/?time=446). In these sorts of scenarios, we often reach for `OperationQueue` and its `maxConcurrentOperationCount` or other similar patterns. – Rob Jan 28 '20 at 16:38
15

The dispatch_get_main_queue should be used anytime you want to manipulate UI elements. This has to do with thread affinity, a common model for UI frameworks. Thread affinity means you can only manipulate the object on the thread on which that object was created. For UI classes in Cocoa Touch, that's the main thread. This is a typical idiom for UI frameworks on all platforms that matter.

So dispatch_get_main_queue gets the queue associated with the main thread. Not doing this causes weird stuff to happen when your UI is updated on a different thread. I typically see long pauses where the UI freezes.

dispatch_get_global_queue gets any old queue of the given priority level associated with your app. Perfect for network calls or, as in your case, working with Core Data.

ageektrapped
  • 14,482
  • 7
  • 57
  • 72
9

Global queue gives you a queue other than the main que but saves you the trouble of actually creating your own queue. Use get_main_queue when you need your code to work on the main queue (where all of your UI work needs to happen)

geraldWilliam
  • 4,123
  • 1
  • 23
  • 35
2
**dispatch_get_main_queue** :- Perform UI updates on this queue

 dispatch_async(dispatch_get_main_queue(), ^{


self.label.text=@"Hello";

    });

**dispatch_get_main_queue**:- Perform background tasks like downloading content

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^{
    for (int i=0; i<100000;enter code here i++) {
        NSLog(@"HIGH 1 %d", i);
    }
});
garg
  • 2,651
  • 1
  • 24
  • 21
  • You passed the priority value to the first, identifier, argument. The flag comes second :) – Julian F. Weinert Aug 05 '18 at 21:00
  • If anyone is still watching this thread I'm trying to do CGRect draw lines and circles in the main_queue area where you're updating the label text. But I get context nil. If I try making it a sync queue it bombs. Any ideas? – user3741598 Jan 29 '20 at 16:16
0

In a brief, dispatch_get_global_queue is used to perform the background task. But when you are performing any task in the background and then if you need to perform any task related to user interface, you need to do it in dispatch_get_main_queue()

Shovo
  • 133
  • 2
  • 9