47 votes

Grand Central Dispatch (GCD) vs performSelector - besoin d'une meilleure explication

J'ai utilisé à la fois GCD et performSelectorOnMainThread: waitUntilDone dans mes applications, et j'ai tendance à les considérer comme interchangeables, c'est-à-dire performSelectorOnMainThread: waitUntilDone est un wrapper Obj-C à la syntaxe GCD. J'ai pensé à ces deux commandes comme équivalentes:

 dispatch_sync(dispatch_get_main_queue(), ^{ [self doit:YES]; });


[self performSelectorOnMainThread:@selector(doit:) withObject:YES waitUntilDone:YES];
 

Est-ce que je me trompe? Autrement dit, existe-t-il une différence entre les commandes performSelector * et celles de GCD? J'ai lu beaucoup de documentation à ce sujet, mais je n'ai pas encore trouvé de réponse définitive.

70voto

Brad Larson Points 122629

Comme Jacob, si elles apparaissent la même, ce sont des choses différentes. En fait, il y a une différence significative dans la façon dont ils gèrent l'envoi d'actions pour le thread principal si vous êtes déjà en cours d'exécution sur le thread principal.

Je suis tombé sur cette récemment, où j'ai eu une méthode commune qui, parfois, a été exécuté à partir de quelque chose sur le thread principal, parfois pas. Afin de protéger certaines mises à jour de l'INTERFACE utilisateur, j'avais été en utilisant -performSelectorOnMainThread: pour eux sans problèmes.

Quand je suis passé à l'aide d' dispatch_sync sur la file d'attente principale, la demande de blocage à chaque fois que cette méthode a été exécuté sur la file d'attente principale. La lecture de la documentation sur dispatch_sync,, nous voyons:

L'appel de cette fonction et de ciblage la file d'attente en cours résultats dans l'impasse.

où pour -performSelectorOnMainThread: nous voir

attendre

Une valeur Booléenne qui spécifie si l' actuel thread se bloque jusqu'à ce que après l' sélecteur de spécifié est effectuée sur la récepteur sur le thread principal. Spécifier OUI pour bloquer ce thread; sinon, spécifiez PAS d'avoir ce retour de méthode immédiatement.

Si le thread courant est également le principal fil, et que vous spécifiez OUI pour cette paramètre, le message est remis et traitées immédiatement.

Je préfère encore l'élégance de PGCD, le meilleur moment de la compilation de vérifier qu'il fournit, et sa grande souplesse concernant les arguments, etc., j'ai donc fait cette petite aide de la fonction pour empêcher les blocages:

void runOnMainQueueWithoutDeadlocking(void (^block)(void))
{
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

Mise à jour: En réponse à Dave Musée en pointant les mises en garde de la section surdispatch_get_current_queue(), je l'ai changé à l'aide d' [NSThread isMainThread] dans le code ci-dessus.

J'utilise ensuite

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

pour effectuer les mesures que j'avais besoin de sécuriser sur le thread principal, sans se préoccuper de ce thread la méthode originale a été exécutée.

22voto

Jacob Relkin Points 90729

performSelectorOnMainThread: ne pas utiliser le PGCD pour envoyer des messages à des objets sur le thread principal.

Voici comment la documentation dit que la méthode est mise en œuvre:

- (void) performSelectorOnMainThread:(SEL) selector withObject:(id) obj waitUntilDone:(BOOL) wait {
  [[NSRunLoop mainRunLoop] performSelector:selector target:self withObject:obj order:1 modes: NSRunLoopCommonModes];
}

Et sur performSelector:target:withObject:order:modes:, les états de documentation:

Cette méthode permet de définir une minuterie pour effectuer le aSelector message sur le thread en cours d'exécution de la boucle au début de la prochaine exécution de la boucle d'itération. La minuterie est configuré pour s'exécuter dans les modes spécifié par le paramètre modes. Lorsque la minuterie se déclenche, le thread tente de retirer le message de l'exécution de la boucle et d'effectuer la sélection. Il réussit si l'exécution de la boucle est en cours d'exécution et dans l'un des modes spécifiés; sinon, la minuterie attend jusqu'à ce que l'exécution de la boucle est dans l'un de ces modes.

2voto

Seyther Points 388

La méthode de GCD est supposée être plus efficace et plus facile à gérer et n’est disponible qu’à partir d’iOS4, tandis que performSelector est pris en charge par les anciens et les plus récents iOS.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X