web-dev-qa-db-fra.com

Bloque au lieu de performSelector: withObject: afterDelay:

Je veux souvent exécuter du code quelques microsecondes à l'avenir. En ce moment, je le résous comme ceci:

- (void)someMethod
{
    // some code
}

Et ça:

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

Cela fonctionne, mais je dois créer une nouvelle méthode à chaque fois. Est-il possible d'utiliser des blocs à la place de cela? Fondamentalement, je recherche une méthode comme:

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

Ce serait vraiment utile pour moi.

87
Rits

Il n'y a pas de moyen intégré de le faire, mais ce n'est pas trop mal d'ajouter via une catégorie:

@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

Nous remercions Mike Ash pour l'implémentation de base.

106
John Calsbeek

Voici une technique simple, basée sur GCD, que j'utilise:

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

Je ne suis pas un expert GCD, et je serais intéressé par des commentaires sur cette solution.

41
Nick Moore

Une autre façon (peut-être la pire façon de le faire pour de nombreuses raisons) est:

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

Si vous avez spécifiquement besoin d'un délai plus long, les solutions ci-dessus fonctionnent très bien. J'ai utilisé l'approche de @ nick avec beaucoup de succès.

Cependant, si vous voulez simplement que votre bloc s'exécute lors de la prochaine itération de la boucle principale, vous pouvez le réduire encore plus avec juste ce qui suit:

[[NSOperationQueue mainQueue] addOperationWithBlock:aBlock];

Cela revient à utiliser performSelector: avec afterDelay de 0.0f

16
Greg Combs

J'ai utilisé un code similaire comme celui-ci:

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

Il y a une catégorie Nice, complète qui gère cette situation ici:

https://Gist.github.com/95512

1
Duane Fields