Blocks instead of performSelector:withObject:afterDelay:
IphoneObjective CCocoa TouchIosObjective C-BlocksIphone 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: