cancel dispatch_after() method?

27,404

Solution 1

There is NO way to prevent a dispatch_block from executing once it has been dispatch to it's queue, meaning that your dispatch_after cannot be canceled. Only option is to add in your block a condition to be checked at runtime to prevent execution. ie.

dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 10 * NSEC_PER_SEC), dispatch_get_main_queue(), ^ {
if(self.shouldExecuteDispatchBlock)
{ // do your stuff }  });

Solution 2

OK, so, with all answers collected, and possible solutions, seems like the best one for this case (preserving simplicity) is calling performSelector:withObject:afterDelay: and cancelling it with cancelPreviousPerformRequestsWithTarget: call when desired. In my case - just before scheduling next delayed call:

[NSObject cancelPreviousPerformRequestsWithTarget: self selector:@selector(myDelayedMethod) object: self];

[self performSelector:@selector(myDelayedMethod) withObject: self afterDelay: desiredDelay];

Solution 3

For this purpose i used this class:

https://github.com/SebastienThiebaud/dispatch_cancelable_block

you can call a cancel() function to revoke the execution of what's in the block.

Solution 4

Use a dispatch timer source (that is what dispatch_after uses internally anyway).

A dispatch timer source can be canceled or its timer parameters changed after creation.

Share:
27,404
Oleg Shanyuk
Author by

Oleg Shanyuk

Making Software

Updated on January 24, 2020

Comments

  • Oleg Shanyuk
    Oleg Shanyuk over 4 years

    Is there a way to cancel dispatch_after() scheduled for some time in future, and haven't fired so far? I'm trying to make something like a scheduler for updates from server, and this method is just like I want, but, I'd love to cancel and re-schedule it at some point. Is it possible at all or I have to fallback and use NSTimer?

  • katleta3000
    katleta3000 about 9 years
    If you would use it in Swift - you can look it here github.com/katleta3000/CancelBlocks
  • Jonny
    Jonny almost 9 years
    Hmmm so until the next time for execution of this block comes up (and it's set to be cancelled), I guess it would hog all the memory/objects until then. Maybe a problem if your cycles are like 60 minutes? :-)
  • Florian Burel
    Florian Burel almost 9 years
    Yes and no. The block copy the memory, wich mean if you refere to a int value in your block, this one will be copied and will stay in memory as a duplicate for as long as the block live. But for object, it does not duplicate them, it copy the adress. MEaning if you refere an image, you will have one UIImage object in the heap but the block will only retain a pointer value (8 bytes in arch64) so, no biggie. Of course the image will be retain in memory untill the block goes out, so it won't be clean by arc.
  • Olie
    Olie over 8 years
    I started down this path, but how does one do it with class methods (which is why I switched to dispatch_after)?
  • Oleg Shanyuk
    Oleg Shanyuk over 8 years
    @Olie good one. Then you have to wrap those calls into instance, or use dispatch + flag (guess, second would be simpler)
  • Nick
    Nick over 7 years
    I have turned this into a extension for DispatchQueue: github.com/nrbrook/DispatchAfterCancellable
  • user963601
    user963601 about 7 years
    Apple introduced dispatch_block_cancel in iOS 8. It asynchronously cancels blocks created with dispatch_block_create. developer.apple.com/reference/dispatch/…
  • MarcWan
    MarcWan almost 6 years
    Does this not require a run loop, however?
  • Oleg Shanyuk
    Oleg Shanyuk almost 6 years
    @MarcWan it is require a run loop - as any call to the performSelector:afterDelay: selectors
  • nmr
    nmr almost 4 years
    Works well for e.g. watchdog timers.