web-dev-qa-db-fra.com

Grand Central Dispatch (GCD) vsSelector - Besoin d'une meilleure explication

J'ai utilisé à la fois GCD et SPRESSELLORONMAINTHREAD: WAITUTINDONE dans mes applications et ont tendance à penser à eux comme interchangeables - c'est-à-dire PerformSelectorOnmainthread: WatintTone est une emballage Obj-C à la syntaxe du GCD C. J'ai pensé à ces deux commandes d'équivalent:

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


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

Suis-je incorrect? C'est-à-dire qu'il y a une différence entre les commandes de SectacleSelector * par rapport aux GCD? J'ai lu beaucoup de documentation sur eux, mais j'ai encore une réponse définitive.

47
akaru

performSelectorOnMainThread: fait non utilise GCD pour envoyer des messages aux objets sur le fil principal.

Voici comment le 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:, la documentation indique:

Cette méthode définit une minuterie pour effectuer le message d'asélectionner sur la boucle d'exécution du thread de courant au début de l'itération de la boucle suivante. La minuterie est configurée pour fonctionner dans les modes spécifiés par le paramètre Modes. Lorsque la minuterie incendie, le fil tente de résoudre le message de la boucle d'exécution et d'effectuer le sélecteur. Il réussit si la boucle d'exécution est en cours d'exécution et dans l'un des modes spécifiés; Sinon, la minuterie attend que la boucle d'exécution soit dans l'un de ces modes.

22
Jacob Relkin

Comme le souligne Jacob, alors qu'ils peuvent apparaître la même chose, ce sont des choses différentes. En fait, il y a une différence significative dans la manière dont ils manipulent d'envoyer des actions au fil principal si vous exécutez déjà sur le fil principal.

Je l'ai rencontré récemment, où j'avais une méthode commune qui a parfois été passée de quelque chose sur le fil principal, parfois pas. Afin de protéger certaines mises à jour de l'interface utilisateur, j'avais utilisé -performSelectorOnMainThread: Pour eux sans problèmes.

Lorsque je suis passé à l'aide de dispatch_sync Sur la file d'attente principale, l'application serait une impasse chaque fois que cette méthode était exécutée sur la file d'attente principale. Lecture de la documentation sur dispatch_sync , nous voyons:

Appeler cette fonction et cibler la file d'attente actuelle entraîne une impasse.

où pour - -performSelectorOnMainThread: Nous voyons

Attendez

Un booléen qui spécifie si le fil de courant bloque jusqu'à une fois le sélecteur spécifié effectué sur le récepteur sur le fil principal. Spécifiez oui pour bloquer ce fil; Sinon, spécifiez aucun pour que cette méthode revienne immédiatement.

Si le thread actuel est également le fil principal et que vous spécifiez YES pour ce paramètre, le message est livré et traité immédiatement.

Je préfère toujours l'élégance de la GCD, la meilleure vérification du temps de compilation fournie et sa plus grande flexibilité concernant les arguments, etc., donc j'ai fait cette petite fonction d'assistance 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 Dribin pointant sur la Section des mises en garde ONdispatch_get_current_queue() , j'ai changé de en utilisant [NSThread isMainThread] Dans le code ci-dessus.

J'utilise ensuite

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});

pour effectuer les actions que j'ai besoin pour sécuriser sur le fil principal, sans vous soucier de ce que la méthode originale a été exécutée.

66
Brad Larson

La voie de Dieu est supposée être plus efficace et plus facile à manipuler et n'est disponible que dans IOS 4, tandis que les performances sont soutenues dans les plus âgées et les plus récentes IOS.

1
Seyther