12 votes

S'assurer que la fonction s'exécute uniquement sur le thread principal

Comment puis-je m'assurer que ma fonction n'est exécutée que sur le thread principal ? Elle met à jour les éléments de l'interface utilisateur.

Une telle fonction est-elle considérée comme "mauvaise" ?

-(void)updateSomethingOnMainThread {
    if ( ![[NSThread currentThread] isEqual:[NSThread mainThread]] )
        [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];
    else {
        // Do stuff on main thread
    }
}

Je l'ai écrit ainsi pour éviter d'avoir une deuxième fonction, initialement je l'avais comme ça :

-(void)updateSomethingOnMainThread_real {
    // Do stuff on main thread
}

-(void)updateSomethingOnMainThread {
    [self performSelectorOnMainThread:@selector(updateSomethingOnMainThread_real) withObject:nil waitUntilDone:NO];
}

17voto

Brad Larson Points 122629

Comme alternative à l'implémentation GCD basée sur les méthodes d'ayoy pour garantir l'exécution sur le thread principal, j'utilise la fonction GCD suivante dans mon code (tirée de une autre de mes réponses ) :

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

Vous pouvez ensuite utiliser cette fonction d'aide n'importe où dans votre code :

runOnMainThreadWithoutDeadlocking(^{
    // Do stuff that needs to be on the main thread
});

Cela garantit que les actions effectuées dans le bloc fermé seront toujours exécutées par le thread principal, quel que soit le thread qui l'appelle. Elle ajoute peu de code et est assez explicite quant au code qui doit être exécuté sur le thread principal.

9voto

logancautrell Points 7508

C'est très bien. Vous pouvez également utiliser GCD pour exécuter du code sur le thread principal.

Consultez cet article de SO.

GCD pour exécuter une tâche dans le thread principal

6voto

Yar Points 25421

J'ai écrit cette simple #define que j'utilise avec beaucoup de succès :

#define ensureInMainThread(); if (!NSThread.isMainThread) { [self performSelectorOnMainThread:_cmd withObject:nil waitUntilDone:NO];    return; }

De cette façon, votre méthode, en supposant qu'elle soit sans paramètre, ressemble à ceci

- (void) updateTheThings {
      ensureInMainThread();
      [self.dog setTailWag:YES];
      // etc...

4voto

ayoy Points 2613

Vous pouvez également utiliser Grand Central Dispatch API mais ce n'est pas très pratique :

-(void)updateSomethingOnMainThread {
    void (^doStuff)(void) = ^{
        // stuff to be done
    };

    // this check avoids possible deadlock resulting from
    // calling dispatch_sync() on the same queue as current one
    dispatch_queue_t mainQueue = dispatch_get_main_queue();
    if (mainQueue == dispatch_get_current_queue()) {
        // execute code in place
        doStuff();
    } else {
        // dispatch doStuff() to main queue
        dispatch_sync(mainQueue, doStuff);
    }
}

sinon, si l'appel synchrone n'est pas nécessaire, vous pouvez appeler dispatch_async() qui est beaucoup plus simple :

-(void)updateSomethingOnMainThread {
    dispatch_async(dispatch_get_main_queue(), ^{
        // do stuff
    });
}

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