Now that dispatch_get_current_queue
is deprecated in iOS 6, how do I use dispatch_after
to execute something in the current queue?
-
Do you need to stay on the same queue or can you use a dispatch to another one (through dispatch_get_global_queue or get_main_queue) – Eric Genet Jul 24 '13 at 16:59
-
Need to stay on the same. – Boon Jul 24 '13 at 17:02
-
3FYI, see http://stackoverflow.com/questions/13237417/alternatives-to-dispatch-get-current-queue-for-completion-blocks-in-ios-6, http://stackoverflow.com/questions/12842166/how-can-i-replace-deprecated-method-dispatch-get-current-queue-from-ios5-to-io, and http://stackoverflow.com/questions/12806506/how-can-i-verify-that-i-am-running-on-a-given-gcd-queue-without-using-dispatch-g for related discussions on this topic. – Rob Jul 24 '13 at 17:14
-
The link above doesn't give a solution. It only says it's better not to do it. I have to do it - also, I don't have control over changing where the calling code is dispatched (it's from a static lib). I need to make sure my code runs in the same queue as the calling code. – Boon Jul 31 '13 at 18:54
-
There's no way to do it with the public API anymore. Explain why you think you have to do it and perhaps we can suggest a different approach. – rob mayoff Aug 01 '13 at 20:41
3 Answers
The various links in the comments don't say "it's better not to do it." They say you can't do it. You must either pass the queue you want or dispatch to a known queue. Dispatch queues don't have the concept of "current." Blocks often feed from one queue to another (called "targeting"). By the time you're actually running, the "current" queue is not really meaningful, and relying on it can (and historically did) lead to dead-lock. dispatch_get_current_queue()
was never meant for dispatching; it was a debugging method. That's why it was removed (since people treated it as if it meant something meaningful).
If you need that kind of higher-level book-keeping, use an NSOperationQueue
which tracks its original queue (and has a simpler queuing model that makes "original queue" much more meaningful).
There are several approaches used in UIKit that are appropriate:
- Pass the call-back dispatch_queue as a parameter (this is probably the most common approach in new APIs). See
[NSURLConnection setDelegateQueue:]
oraddObserverForName:object:queue:usingBlock:
for examples. Notice thatNSURLConnection
expects anNSOperationQueue
, not adispatch_queue
. Higher-level APIs and all that. - Call back on whatever queue you're on and leave it up to the receiver to deal with it. This is how callbacks have traditionally worked.
- Demand that there be a runloop on the calling thread, and schedule your callbacks on the calling runloop. This is how
NSURLConnection
historically worked before queues. - Always make your callbacks on one of the well-known queues (particularly the main queue) unless told otherwise. I don't know of anywhere that this is done in UIKit, but I've seen it commonly in app code, and is a very easy approach most of the time.

- 286,113
- 34
- 456
- 610
-
2I have some gripes with your last statement: if this is a callback (say a completion, error or progress handler) then the *main queue* should be the least candidate to be selected as the default execution context. Using the main queue increases the probability for dead locks. This is a bad habit from library designers, stemming from the stupid and false assumption, that the client of the async task want's to do stuff on the main thread "anyway". But that makes it just worse. – CouchDeveloper Aug 08 '13 at 10:23
Create a queue manually and dispatch both your calling code and your dispatch_after
code onto that. That way you can guarantee that both pieces of code are run from the same queue.

- 129
- 8
-
Let's assume I cannot dispatch my calling code, say it's from a static library. – Boon Jul 31 '13 at 18:53
-
In that case, would some indirection help? Rather than passing the code you want called, have a wrapper of your own that dispatches to the correct queue. – Gary Makin Aug 01 '13 at 04:21
Having to do this is likely because the need of a hack. You can hack around this with another hack:
id block = ^foo() {
[self doSomething];
usleep(delay_in_us);
[self doSomehingOther];
}
Instead of usleep()
you might consider to loop in a run loop.
I would not recommend this "approach" though. The better way is to have some method which takes a queue as parameter and a block as parameter, where the block is then executed on the specified queue.
And, by the way, there are ways during a block executes to check whether it runs on a particular queue - respectively on any of its parent queue, provided you have a reference to that queue beforehand: use functions dispatch_queue_set_specific
, and dispatch_get_specific
.

- 18,174
- 3
- 45
- 67