21

I am new in ios development. I have following questions:

  1. When we use GCD(dispatch_group_async, dispatch_async(dispatch_get_main_queue()...) and when we use performSelectorInBackground/performSelectorOnMainThread?
  2. What's the differences between those two.

    I know when we use performSelectorInBackground, we create a new NSThread. But isn't the same when we use dispatch_group_async? Because if we create more than one dispatch_group_async, it means we need to submit more than one blocks in queue. And those blocks might run on different queues. Therefore, when we create more than one dispatch_group_async, does it means we create a new thread? (because blocks may run on different queues) (I kind of confused about NSThread and block queue.....)

Thanks!!

Gabriele Petronella
  • 106,943
  • 21
  • 217
  • 235
YU FENG
  • 888
  • 1
  • 12
  • 29

2 Answers2

34

When to use performSelectorInBackground:

Never. Do not use this method. It spawns an unbounded number of threads. Even before GCD was available, this was a horrible method.

When to use performSelectorOnMainThread:

Meh… Never, but just because it's inconvenient. There's nothing deeply wrong with this method. It's just not as useful as dispatch_async().

The difference between GCD and the old performSelector… methods (and NSThread in general) is that GCD manages a thread pool for you. In general, you should avoid manual threading in Cocoa. Instead, use NSOperationQueue or GCD (dispatch methods). They provide a more useful queue abstraction rather than forcing you to manually manage threads.

Be sure to read over Apple's Migrating Away from Threads for more info.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610
  • dispatch_[a]sync to the main queue is not as equivalent as you might think. It ties your code to the main runloop being serviced non-reentrantly. There are plenty of (relatively obscure, to be fair) situations where dispatch will produce different results than CFRunLoopPerformBlock or performSelectorOnMainThread. – Catfish_Man Oct 21 '13 at 18:34
  • @Catfish_Man, I agree that there are some subtle differences, especially on Mac. When NSAttributedString converts HTML, it pumps the runloop, which can cause deadlock if you've scheduled other things on the main runloop already. And there's always the tricky situation of runloop modes and scrolling. All of them point you towards using GCD or operation queues IMO, so the advice doesn't change. The convenience alone is mostly the reason to avoid performSelectonOnMainThread:, and you can consider some of the obscure corner cases in runloops to be a subset of "inconvenient." – Rob Napier Oct 21 '13 at 20:36
  • 2
    Yeah, I'm not really trying to point towards or away from a specific API. Just cautioning that they aren't strictly drop-in replacements for each other. – Catfish_Man Oct 21 '13 at 20:40
  • Should I even use `dispatch_async()` to simply `show` a `UIAlertView` from an `[NSURLSession sharedSession].delegateQueue`? [Brian Coleman says to use `performSelectorOnMainThread:withObject:waitUntilDone:` to update the UI from a background thread](http://www.brianjcoleman.com/tutorial-threading/). – ma11hew28 Apr 27 '14 at 17:09
  • I'd do that one with `dispatch_async`, too. Then you could move all the `UI*` methods to the main thread. And it's easier to see what's happening in a `dispatch_async` (the `show` isn't buried in a selector). While the `init` is probably safe on the background, it's better to just move all UIKit stuff to the main thread unless you have a strong reason not to. Then you don't have to research every UIKit call to double-check. BTW, "seems to work" is meaningless for thread-safety. High unsafe code can work thousands of times correctly, and still crash in the field. – Rob Napier Apr 27 '14 at 19:40
2

Actually after iOS 4.0 I can't find any single reason to use performSelectorInBackground/onMainThread. If you need to do something in background, use GCD( or, better, NSOperationQueue which is built on top of GCD since 4.0 and gives greater flexibility with little overhead), but be sure not to create retain cycles when using blocks.

Timur Kuchkarov
  • 1,155
  • 7
  • 21
  • 1
    dispatch_[a]sync to the main queue is not as equivalent as you might think. It ties your code to the main runloop being serviced non-reentrantly. There are plenty of (relatively obscure, to be fair) situations where dispatch will produce different results than CFRunLoopPerformBlock or performSelectorOnMainThread. – Catfish_Man Oct 21 '13 at 18:35
  • @Catfish_Man, would be interesting to know more about those situations. – Timur Kuchkarov Oct 21 '13 at 18:37
  • @Catfish_Man Could you please elaborate, or link to relevant questions and or sources? Thanks – Léo Natan Oct 21 '13 at 18:37
  • One issue is obliquely mentioned here: https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man3/dispatch_get_main_queue.3.html, where it says "Blocks submitted to the main queue will be executed as part of the "common modes" of the application's main NSRunLoop or CFRunLoop". So if your runloop is not running in the common modes, then blocks on the main queue will not execute. – Catfish_Man Oct 21 '13 at 20:27
  • For the other issue, this bit from the CFRunLoop docs alludes to it: "Run loops can be run recursively. You can call CFRunLoopRun or CFRunLoopRunInMode from within any run loop callout and create nested run loop activations on the current thread’s call stack. You are not restricted in which modes you can run from within a callout. You can create another run loop activation running in any available run loop mode, including any modes already running higher in the call stack". That's not true of dispatch queues, including the main queue. – Catfish_Man Oct 21 '13 at 20:30
  • @catfish_man See my comments on my answer for some specific cases where this happens. I haven't seen any of these crop up on iOS, however. Only Mac. Do you have any iOS examples? – Rob Napier Oct 21 '13 at 20:38
  • Also, are you aware of any cases where you'd *want* the performSelectorOnMainThread: behavior over the dispatch_async to main_queue behavior? – Rob Napier Oct 21 '13 at 20:39
  • The Foundation-layer stuff is the same on both platforms, so the differences certainly exist in principle; I've been disconnected from UI stuff for long enough that I don't recall which places they might be encountered in practice on iOS. – Catfish_Man Oct 21 '13 at 20:40