it-swarm.com.ru

Блокирует вместо executeSelector: withObject: afterDelay:

Я часто хочу выполнить некоторый код через несколько микросекунд в будущем. Прямо сейчас я решаю это так:

- (void)someMethod
{
    // some code
}

И это:

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

Это работает, но я должен каждый раз создавать новый метод. Можно ли вместо этого использовать блоки? В основном я ищу такой метод, как:

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

Это было бы действительно полезно для меня.

87
Rits

Там нет встроенного способа сделать это, но это не так уж плохо, чтобы добавить через категорию:

@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

Благодарим Майк Эш за базовую реализацию.

106
John Calsbeek

Вот простая техника, основанная на 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, и мне было бы интересно получить комментарии по этому решению.

41
Nick Moore

Другой способ (возможно, худший способ сделать это по многим причинам):

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

Если вам требуется более длительная задержка, вышеприведенные решения работают просто отлично. Я использовал подход @ nick с большим успехом.

Однако, если вы просто хотите, чтобы ваш блок работал во время следующей итерации основного цикла, вы можете укоротить его еще дальше, просто выполнив следующее:

[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];

Это похоже на использование executeSelector: afterDelay = 0.0f

16
Greg Combs

Я использовал подобный код, как это:

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

Есть хорошая, полная категория, которая обрабатывает эту ситуацию здесь:

https://Gist.github.com/95512

1
Duane Fields