Блоки вместо performSelector: withObject: afterDelay:
Я часто хочу выполнить код в несколько микросекунд в будущем. Сейчас я решаю это так:
- (void)someMethod
{
// some code
}
И это:
[self performSelector:@selector(someMethod) withObject:nil afterDelay:0.1];
Это работает, но я должен каждый раз создавать новый метод. Можно ли использовать блоки вместо этого? В основном я ищу способ вроде:
[self performBlock:^{
// some code
} afterDelay:0.1];
Это было бы очень полезно для меня.
Ответы
Ответ 1
Нет никакого встроенного способа сделать это, но это не так уж сложно добавить через категорию:
@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
Кредит Майк Эш для базовой реализации.
Ответ 2
Вот простой метод, основанный на GCD, который я использую:
void RunBlockAfterDelay(NSTimeInterval delay, void (^block)(void))
{
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, NSEC_PER_SEC*delay),
dispatch_get_current_queue(), block);
}
Я не эксперт GCD, и мне было бы интересно получить комментарии к этому решению.
Ответ 3
Другой способ (возможно, худший способ сделать это по многим причинам):
[UIView animateWithDuration:0.0 delay:5.0 options:UIViewAnimationOptionAllowUserInteraction animations:^{
} completion:^(BOOL finished) {
//do stuff here
}];
Ответ 4
Если вам нужна более длительная задержка, решения выше работают очень хорошо. Я использовал @nick подход с большим успехом.
Однако, если вы просто хотите, чтобы ваш блок работал во время следующей итерации основного цикла, вы можете еще больше обрезать его следующим образом:
[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];
Это сродни использованию функции performSelector: с afterDelay 0.0f
Ответ 5
Я использовал аналогичный код:
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...
});
Ответ 6
Вот хорошая, полная категория, которая обрабатывает эту ситуацию здесь:
https://gist.github.com/955123