web-dev-qa-db-fra.com

GCD pour effectuer la tâche dans le thread principal

J'ai un rappel qui peut provenir de n'importe quel fil. Lorsque je reçois ce rappel, je voudrais effectuer une certaine tâche sur le thread principal.

Dois-je vérifier si je suis déjà sur le thread principal - ou existe-t-il une pénalité en n'effectuant pas cette vérification avant d'appeler le code ci-dessous?

dispatch_async(dispatch_get_main_queue(), ^{
   // do work here
});
218
Egil

Non, vous n’avez pas besoin de vérifier si vous êtes déjà sur le fil principal. En envoyant le bloc dans la file d'attente principale, vous ne faites que planifier l'exécution du bloc en série sur le thread principal, ce qui se produit lorsque la boucle d'exécution correspondante est exécutée.

Si vous êtes déjà sur le thread principal, le comportement est le même: le bloc est planifié et exécuté lors de l'exécution de la boucle d'exécution du thread principal.

141
user557219

Pour le cas de répartition asynchrone que vous décrivez ci-dessus, vous ne devriez pas avoir besoin de vérifier si vous êtes sur le thread principal. Comme Bavarious l'indique, cela sera simplement mis en file d'attente pour être exécuté sur le thread principal.

Toutefois, si vous tentez d'effectuer la procédure ci-dessus à l'aide d'une dispatch_sync() et que votre rappel est sur le thread principal, votre application se bloquera à ce stade. Je décris cela dans ma réponse ici , car ce comportement m'a surpris lors du déplacement de code de -performSelectorOnMainThread:. Comme je le mentionne ici, j'ai créé une fonction d'assistance:

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

qui exécutera un bloc de manière synchrone sur le thread principal si la méthode dans laquelle vous vous trouvez n’est pas actuellement sur le thread principal et n’exécute que le bloc en ligne s’il l’est. Vous pouvez utiliser une syntaxe comme celle-ci pour l'utiliser:

runOnMainQueueWithoutDeadlocking(^{
    //Do stuff
});
96
Brad Larson

Comme mentionné dans les autres réponses, dispatch_async à partir du thread principal est correct.

Cependant, en fonction de votre cas d'utilisation, il existe un effet secondaire que vous pouvez considérer comme un inconvénient: comme le bloc est planifié dans une file d'attente, il ne s'exécutera pas tant que le contrôle ne sera pas retourné à la boucle d'exécution, ce qui aura pour effet de retarder l'exécution de votre bloc.

Par exemple,

NSLog(@"before dispatch async");
dispatch_async(dispatch_get_main_queue(), ^{
    NSLog(@"inside dispatch async block main thread from main thread");
});
NSLog(@"after dispatch async");

Imprimera:

before dispatch async
after dispatch async
inside dispatch async block main thread from main thread

Pour cette raison, si vous vous attendiez à ce que le bloc s'exécute entre les journaux NSLog externes, dispatch_async ne vous aiderait pas.

47
Michael Chinen

Non, vous n'avez pas besoin de vérifier si vous êtes dans le fil principal. Voici comment vous pouvez le faire dans Swift:

runThisInMainThread { () -> Void in
    runThisInMainThread { () -> Void in
        // No problem
    }
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Son inclus en tant que fonction standard dans mon référentiel, consultez-le: https://github.com/goktugyil/EZSwiftExtensions

1
Esqarrouth