21

The only functional difference I have encountered is that I can cancel the message scheduled with performSelector:withObject:afterDelay:. I don't know of a way to cancel a block submitted to dispatch_after. (Please let me know if there is a way to do this that I do not know about).

I'd like to know more about:

  • functional tradeoffs (What else can be accomplished with one interface but not the other?)
  • performance tradeoffs (Is one implementation more efficient? In which cases?)
  • stylistic tradeoffs (Should I prefer one interface for certain tasks to better follow common styles or conventions?)
sergio
  • 68,819
  • 11
  • 102
  • 123
Andrew Hershberger
  • 4,152
  • 1
  • 25
  • 35

2 Answers2

19

dispatch_after is part of the new Grand Central Dispatch, which is an extension to iOS aimed at improving concurrent code execution on multicore hardware.

But overall, I think they address different requirements overall. GCD allows to a much finer graded control over concurrent execution of code. You can schedule blocks on a queue, remove them, suspend, resume, etc. It is a broader topic to be considered here in general. Also, GCD provides many more synchronization options.

As far as the comparison with performSelector, I think that one advantage dispatch_after rightly has is the possibility of scheduling a block without the need to define a selector. See this discussion.

On in all, I haven't got much experience with GCD, but I would say that apart from the block scheduling thing, when you simply need to delay some selector execution in your UI, without much a requirement for concurrency in general, I would use performSelector.

If you think about it, performSelector gives you a very poor concurrency, since it simply schedules your selector for execution on the run loop after a minimum amount of time. On the other hand, dispatch_after gives you a control which seems in principle at the level of nanoseconds (!! this is what I get from Apple docs, but I have never used it and I don't think that on an iPhone you would get that, possibly on MacOS).

EDIT: about unscheduling a block, I have never tried to unschedule a block from a queue, but there is a possibility that dispatch_release also allows you to control that. If it does not, you could define your custom queue for the block that you want to cancel and release the whole queue (before the block starts being executed), if that ever makes sense to you.

As to performance, I really don't know what performSelector does inside, but if it schedules a thread, then Apple states that scheduling a block with GCD only costs 15 instructions, while creating a thread costs several hundred of them.

Apart from performSelector, don't forget you have the option of using NSOperationQueue, which is based on GCD, and has some overhead overt it but not that big, they say. NSOperationQueue certainly offers the possibility of cancelling.

Community
  • 1
  • 1
sergio
  • 68,819
  • 11
  • 102
  • 123
  • Thanks for the reply. I've never seen a way to remove blocks once they are scheduled on a queue. Can you provide more details? Also, aside from concurrency, is one interface more efficient than the other for serial execution? – Andrew Hershberger Jun 02 '11 at 00:50
  • 2
    If I understand sergio correctly, he suggests that releasing a queue would cancel all pending blocks from executing. This isn't so... See http://developer.apple.com/library/mac/#documentation/Performance/Reference/GCD_libdispatch_Ref/Reference/reference.html which says: When your application no longer needs the dispatch queue, it should release it with the dispatch_release function. Any pending blocks submitted to a queue hold a reference to that queue, so the queue is not deallocated until all pending blocks have completed. – Jason Jun 26 '11 at 17:59
  • 5
    you can also create a gcd timer, which is cancelable: http://www.fieryrobot.com/blog/2010/07/10/a-watchdog-timer-in-gcd/ – jasongregori Aug 12 '11 at 22:03
  • `Note: Even if you specify a leeway value of 0, you should never expect a timer to fire at the exact nanosecond you requested. The system does its best to accommodate your needs but cannot guarantee exact firing times.` from apple docs: http://developer.apple.com/library/ios/#documentation/General/Conceptual/ConcurrencyProgrammingGuide/GCDWorkQueues/GCDWorkQueues.html#//apple_ref/doc/uid/TP40008091-CH103-SW2 – bearMountain Apr 11 '12 at 20:39
  • Scheduling a block with GCD costing 15 instructions refers to dispatch_async, not dispatch_after. dispatch_after will be much slower than that, as anything that uses timers will be. – Catfish_Man Jul 19 '13 at 01:48
4

Another big advantage of using GCD instead of performSelector is the ability to very simply use multiple local variables as part of the block operation. If you want to defer the execution of a method that takes more than one argument until a later time using performSelector, you have to wrap the arguments you want to use in another object, such as an array. With dispatch_after you can very simply pass any number of local variables to the block. This also applies to non-objects, which you can't pass to a performSelector call without first wrapping in an object, such as an NSValue for passing a CGRect. GCD lets you pass primitives, structs, and objects to the operation you want to defer.

KlimczakM
  • 12,576
  • 11
  • 64
  • 83
Ben M.
  • 430
  • 2
  • 11