Blocks instead of performSelector:withObject:afterDelay:

IphoneObjective CCocoa TouchIosObjective C-Blocks

Iphone Problem Overview


I often want to execute some code a few microseconds in the future. Right now, I solve it like this:

- (void)someMethod
{
    // some code
}

And this:

[self performSelector:@selector(someMethod) withObject:nil afterDelay:0.1];

It works, but I have to create a new method every time. Is it possible to use blocks instead of this? Basically I'm looking for a method like:

[self performBlock:^{
    // some code
} afterDelay:0.1];

That would be really useful to me.

Iphone Solutions


Solution 1 - Iphone

There's no built-in way to do that, but it's not too bad to add via a category:

@implementation NSObject (PerformBlockAfterDelay)

- (void)performBlock:(void (^)(void))block 
          afterDelay:(NSTimeInterval)delay 
{
    block = [[block copy] autorelease];
    [self performSelector:@selector(fireBlockAfterDelay:) 
               withObject:block 
               afterDelay:delay];
}

- (void)fireBlockAfterDelay:(void (^)(void))block {
    block();
}

@end

Credit to Mike Ash for the basic implementation.

Solution 2 - Iphone

Here's a simple technique, based on GCD, that I'm using:

void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
	dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
      dispatch_get_current_queue(), block);
}

I'm not a GCD expert, and I'd be interested in comments on this solution.

Solution 3 - Iphone

Another way (perhaps the worst way to do this for many reasons) is:

[UIView animateWithDuration:0.0 delay:5.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished) {
	//do stuff here
}];

Solution 4 - Iphone

If you specifically need a longer delay, the solutions above work just fine. I've used @nick's approach with great success.

However, if you just want your block to run during the next iteration of the main loop, you can trim it down even further with just the following:

[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];

This is akin to using performSelector: with afterDelay of 0.0f

Solution 5 - Iphone

I used similar code like this:

double delayInSeconds = 0.2f;
dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delayInSeconds * NSEC_PER_SEC));
dispatch_after(popTime, dispatch_get_main_queue(), ^(void){
      //whatever you wanted to do here...  
    });

Solution 6 - Iphone

There's a nice, complete category that handles this situation here:

https://gist.github.com/955123

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRitsView Question on Stackoverflow
Solution 1 - IphoneJohn CalsbeekView Answer on Stackoverflow
Solution 2 - IphoneNick MooreView Answer on Stackoverflow
Solution 3 - IphoneninjaneerView Answer on Stackoverflow
Solution 4 - IphoneGreg CombsView Answer on Stackoverflow
Solution 5 - IphoneDespotovicView Answer on Stackoverflow
Solution 6 - IphoneDuane FieldsView Answer on Stackoverflow