2010-01-17 8 views
1

Considérez ceci:Comment optimiser callbacks d'un fil NSOperationQueue-commencé

@interface SomeViewController : UIViewController { 
    SomeChildObject *child; 
} 
@end 

@implementation SomeViewController 

- (void) viewDidLoad { 
    ... 
    child.delegate = self; 
} 

- (void) somethingHappened { 
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] 
     initWithTarget:child 
     selector:@selector(doSomething) 
     object:nil]; 
[someNsOperationQueue addOperation:operation]; 
[operation release]; 
} 

- (void) callbackA:(SomeData *)someData { 
[self performSelectorOnMainThread:@selector(callbackAonMainThread:) 
         withObject:someData 
        waitUntilDone:NO]; 
} 

- (void) callbackAonMainThread:(SomeData *)someData { 
    ... do something with results in main thread, e.g UI feedback 
} 

- (void) callbackB:(SomeData *)someData { 
[self performSelectorOnMainThread:@selector(callbackBonMainThread:) 
         withObject:someData 
        waitUntilDone:NO]; 
} 

- (void) callbackBonMainThread:(SomeData *)someData { 
    ... do something with results in main thread, e.g UI feedback 
} 


@end 

En anglais:

J'ai un contrôleur de vue en cours d'exécution dans le thread principal avec un objet modèle enfant à faire quelque chose (fetch données sur le réseau). Le contrôleur de vue est le délégué de l'enfant, de sorte que l'enfant peut renvoyer les résultats avec la délégation. Pour effectuer le travail coûteux, je génère la méthode child.doSomething avec un NSInvocationOperation qui lance l'opération dans un thread d'arrière-plan. Quand cela est fait, l'enfant appelle le callbackA ou le callbackB du délégué (voir le contrôleur) avec quelques résultats. Puisque (je pense) ces rappels sont invoqués dans le même thread d'arrière-plan où l'appel doSomething a été exécuté, j'ai besoin d'appeler performSelectorOnMainThread pour transférer le contrôle au thread principal.

Cela fonctionne bien, mais je n'aime pas avoir deux méthodes liées au rappel pour chaque rappel. (Il y a en fait plus callbacks, de sorte que le code réel est encore plus pléthorique.) Dans l'idéal, je ferais quelque chose comme ceci:

- (void) callbackA:(SomeData *)someData { 
    if (not_running_on_main_thread) { 
    [self performSelectorOnMainThread:@selector(callbackA:) 
         withObject:someData 
        waitUntilDone:NO]; 
    } else { 
     // now running on main thread, work with the results. 
    } 
} 

Questions:

1) comment dois-je faire le test "not_running_on_main_thread" ? 2) Y a-t-il un autre moyen de réduire les ballonnements de rappel?

EDIT: ok, je ne lis jamais les documents NSThread avant de poster :) ressemble à [NSThread isMainThread] est ce que je cherche. Mais y a-t-il un autre moyen de restructurer ou de rendre encore plus agréable?

Répondre

6

Vérifiez simplement [NSThread isMainThread]. Il n'y a rien de plus que vous pouvez faire si vous avez besoin de plusieurs rappels qui font des choses différentes.

Une seule chose que je fais différemment, mon code ressemble à ceci:

- (void) callbackA:(SomeData *)someData { 
    if (![NSThread isMainThread]) { 
     [self performSelectorOnMainThread:@selector(callbackA:) 
         withObject:someData 
        waitUntilDone:NO]; 
     return; 
    } 

    // now running on main thread, work with the results. 
} 

Cela me permet de me débarrasser de toute fonction long else et rendre le code un peu plus clair. Et vous pouvez économiser sur un niveau d'indentation de cette façon ;-)

+0

Bon conseil pour le retour. J'aime le joli code. – Jaanus