块,而不是 PerformSelector: withObject: after 延迟:

我经常想在将来几微秒内执行一些代码,现在我是这样解决的:

- (void)someMethod
{
// some code
}

还有这个:

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

它能工作,但是每次我都要创建一个新的方法。有没有可能用块代替这个?基本上,我在寻找一种方法,比如:

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

那对我很有用。

39327 次浏览

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.

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.

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

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
}];

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

https://gist.github.com/955123

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...
});