How to remove queued block from a GCD dispatch queue?

10,465

Solution 1

You cannot remove or otherwise change an operation enqueued on a dispatch queue. Try using the higher level NSOperationQueue instead which supports cancellation.

Solution 2

This can easily be done with GCD as well, no need to reach for the big hammer that is NSOperationQueue here.

Just use a non-repeating dispatch timer source directly instead of dispatch_after (which is just a convenience wrapper around such a timer source, it doesn't actually enqueue the block onto the queue until the timer goes off).

You can reschedule a pending timer source execution with dispatch_source_set_timer().

Share:
10,465
Gökhan Barış Aker
Author by

Gökhan Barış Aker

about me. :)

Updated on July 10, 2022

Comments

  • Gökhan Barış Aker
    Gökhan Barış Aker almost 2 years

    I am trying to re-schedule queued block that will handle the update operations. Main goal is updating UI objects (online user table...) with minimum amount of (UI update request). (Server sometimes rain down massive amount of updates, yay!)

    For simplicity main scenario is;

    • The dispatch_queue_t instance (queue that will handle given UI updating block) is a serial dispatch queue (private dispatch queue)

    • The operation (UI updating block) is scheduled with dispatch_after with t amount of time (Instead of updating for each data set update, collect update requests within t amount of time and perform a single UI update for them)

    • In case our data set updated, check if there already exist a scheduled event. If yes, unschedule it from dispatch_queue_t instance. Then re-schedule same block with t amount of time delay.

    Also;

    t is a small amount of time interval that possibly won't be noticed by the user (like 500 ms.) Any alternative approach is welcome.

    My motive behind this;

    i applied same logic via Android's Handler (post & removeCallbacks combination with Runnable instance) and i hope i could achieve the same on iOS.

    Edit:

    As @Sven suggested usage of NSOperationQueue is more suitable for the scenario as they support cancelling each NSOperation. I skimmed through documents and found;

    Canceling Operations Once added to an operation queue, an operation object is effectively owned by the queue and cannot be removed. The only way to dequeue an operation is to cancel it. You can cancel a single individual operation object by calling its cancel method or you can cancel all of the operation objects in a queue by calling the cancelAllOperations method of the queue object.

    You should cancel operations only when you are sure you no longer need them. Issuing a cancel command puts the operation object into the “canceled” state, which prevents it from ever being run. Because a canceled operation is still considered to be “finished”, objects that are dependent on it receive the appropriate KVO notifications to clear that dependency. Thus, it is more common to cancel all queued operations in response to some significant event, like the application quitting or the user specifically requesting the cancellation, rather than cancel operations selectively.

  • Gökhan Barış Aker
    Gökhan Barış Aker about 11 years
    I always wanted to take a look at NSOperationQueue's as they are heavily used at AFNetworking framework. Thanks, i will take a look and mark as a answer, if possible.
  • Tricertops
    Tricertops about 11 years
    NSOperationQueue is just Objective-C wrapper around GCD queues. Why do you think it's “big hammer”? It has also simplier interface for me so I prefer it.
  • das
    das about 11 years
    That is incorrect. NSOperationQueue is not a GCD wrapper, it is a very complex queueing, dependency and priority tracking system implemented completely separately from GCD. It uses GCD internally for some synchronization (along with spinlocks and mutexes) but in terms of execution of client code the only connection to GCD is that NSOperationQueue does a dispatch_async() to the global concurrent queue at the end to execute an operation once it is ready to do so. All this complexity & flexibility comes at a cost, NSOperationQueue is 1000s of times slower than GCD for simple operations.
  • quellish
    quellish about 11 years
    NSOperation IS a higher level concurrency wrapper around GCD that uses KVO and GCD primitives to manage dependancies within the queue. QA1712, the NSOperationQueue class reference, as well as the Concurrency Programming Guide all mention this. NSOperations should NOT be "1000s" of times slower than GCD for simple operations (i.e. addOperationWithBlock). If it is, you are doing something else wrong.
  • das
    das about 11 years
    Sorry, there is no "wrapping", NSOperationQueue does not have equivalent concepts to those of GCD aside from the basic idea of queueing (and even that is not exactly the same and is not implemented on top of a GCD queue internally). This is not at all surprising since the design of the NSOperationQueue API predates that of GCD by several years. As far as the performance differential goes, feel free to measure it yourself... If you think the documentation is misleading on these points, please file a bug at bugreporter.apple.com
  • d2burke
    d2burke about 9 years
    lol @quellish -> linkedin.com/in/danielsteffen. I think this guy knows what he's talking about :)