Objective-C delay action with blocks
Asked Answered
E

4

53

I know that there are several ways of delaying an action in Objective-C like:

performSelector:withObject:afterDelay:

or using NSTimer.

But there is such a fancy thing called blocks where you can do something like this:

[UIView animateWithDuration:1.50 delay:0 options:(UIViewAnimationOptionCurveEaseOut|UIViewAnimationOptionBeginFromCurrentState) animations:^{

    }completion:^(BOOL finished){
}];

Unfortunately, this method applies only to animating things.

How can I create a delay with a block in one method so I don't have to use all those @selectors and without the need to create a new separate method? Thanks!

Engaging answered 14/3, 2013 at 15:10 Comment(7)
Will this help you ? #15219361Deme
why do you afraid of creating a separate method ? this will solve the problem immediately.Oppose
@ShivanRaptor because I have a lot of methods already and I wanted to find a better wayEngaging
i dont sure it will work but you can try calling methods inside completion:^(BOOL finished){ } blockLindberg
Is your problem a warning or error you're not mentioning here?Haustellum
@StevenFisher the problem is written in the end of the postEngaging
Ah, my problem was just that I misread your code sample. :) You discovered things in a very strange order, but this is a good question. Thanks for posting it.Haustellum
I
143

use dispatch_after:

double delayInSeconds = 2.0;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
    //code to be executed on the main queue after delay
    [self doSometingWithObject:obj1 andAnotherObject:obj2];
});
Iou answered 14/3, 2013 at 15:13 Comment(2)
well it improves readability a lot - especially when you use blocks as method parametersIou
It would be nice to hide this (especially popTime calculation) in a function/method, e.g [NSObject performBlock:afterDelay:];Mosaic
I
25

Expanding on the accepted answer, I created a Helper function for anyone who doesn't care to memorize the syntax each time they want to do this :) I simply have a Utils class with this:

Usage:

[Utils delayCallback:^{
     //--- code here
} forTotalSeconds:0.3];

Helper method:

+ (void) delayCallback: (void(^)(void))callback forTotalSeconds: (double)delayInSeconds{

     dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, delayInSeconds * NSEC_PER_SEC);
     dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
           if(callback){
                callback();
           }
      });
}
Infection answered 28/3, 2014 at 0:47 Comment(0)
T
3

Xcode 11.3.1 (at least, and also other versions of Xcode) provides a code snippet to do this where you just have to enter the delay value and the code you wish to run after the delay.

  1. click on the + button at the top right of Xcode.
  2. search for after
  3. It will return only 1 search result, which is the desired snippet (see screenshot). Double click it and you're good to go.

screenshot illustrating how to get the snippet from within Xcode itself

Trowbridge answered 18/6, 2020 at 13:20 Comment(1)
Wow! The crazy stuff you find hidden in XCode!Useful
J
1

Here is how you can trigger a block after a delay in Swift:

runThisAfterDelay(seconds: 4) { () -> () in
    print("Prints this 4 seconds later in main queue")
    // Or just call animatedMyObject() right here
}

/// EZSwiftExtensions
func runThisAfterDelay(seconds seconds: Double, after: () -> ()) {
    let time = dispatch_time(DISPATCH_TIME_NOW, Int64(seconds * Double(NSEC_PER_SEC)))
    dispatch_after(time, dispatch_get_main_queue(), after)
}

Its included as a standard function in my repo: https://github.com/goktugyil/EZSwiftExtensions

Joeannjoed answered 1/12, 2015 at 22:30 Comment(1)
Wrong language. Question was about Obj-CGow

© 2022 - 2024 — McMap. All rights reserved.