dispatch_async et l'appel d'un gestionnaire d'achèvement dans la queue d'origine

J'ai vu quelques questions connexes mais aucune ne semble répondre à ce cas. Je veux écrire une méthode qui fonctionnera en arrière-plan. J'ai besoin de cette méthode pour appeler un callback d'achèvement sur le même thread / queue utilisé pour l'appel de méthode d'origine.

- (void)someMethod:(void (^)(BOOL result))completionHandler { dispatch_queue_t current_queue = // ??? // some setup code here dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BOOL ok = // some result // do some long running processing here dispatch_async(current_queue, ^{ completionHandler(ok); }); }); 

Quelle incantation magique est nécessaire ici pour que le gestionnaire d'achèvement soit appelé sur la même queue ou le même thread que l'appel à sameMethod ? Je ne veux pas assumer le fil principal. Et bien sûr, dispatch_get_current_queue ne doit pas être utilisé.

Si vous regardez à travers les documents Apple, il semble y avoir deux templates.

S'il est supposé que le gestionnaire d'achèvement doit être exécuté sur le thread principal, aucune queue ne doit être fournie. Un exemple serait animations methods d' animations UIView :

 + (void)animateWithDuration:(NSTimeInterval)duration animations:(void (^)(void))animations completion:(void (^)(BOOL finished))completion 

Sinon, l'API request généralement à l'appelant de fournir une queue:

 [foo doSomethingWithCompletion:completion targetQueue:yourQueue]; 

Ma suggestion est de suivre ce model. Si l'on ne sait pas quelle queue le gestionnaire d'achèvement doit être appelé, l'appelant doit le fournir explicitement en tant que paramètre.

Vous ne pouvez pas vraiment utiliser les files d'attente pour cela car, en dehors de la queue principale, aucune d'entre elles ne peut être exécutée sur un thread particulier. Au lieu de cela, vous devrez get le fil et exécuter votre bloc directement là.

Adaptation de Block Additions de Mike Ash :

 // The last public superclass of Blocks is NSObject @implementation NSObject (rmaddy_CompletionHandler) - (void)rmaddy_callBlockWithBOOL: (NSNumber *)b { BOOL ok = [b boolValue]; void (^completionHandler)(BOOL result) = (id)self; completionHandler(ok); } @end 

 - (void)someMethod:(void (^)(BOOL result))completionHandler { NSThread * origThread = [NSThread currentThread]; dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ BOOL ok = // some result // do some long running processing here // Check that there was not a nil handler passed. if( completionHandler ){ // This assumes ARC. If no ARC, copy and autorelease the Block. [completionHandler performSelector:@selector(rmaddy_callBlockWithBOOL:) onThread:origThread withObject:@(ok) // or [NSNumber numberWithBool:ok] waitUntilDone:NO]; } }); }); 

Bien que vous n'utilisiez pas dispatch_async() , cela rest asynchronous par rapport au rest de votre programme, car il est contenu dans le bloc de tâches dissortingbué d'origine, et waitUntilDone:NO rend également asynchronous par rapport à cela.

Vous ne savez pas si cela va résoudre le problème, mais qu'en est-il de l'utilisation de NSOperations au lieu de GCD?

 - (void)someMethod:(void (^)(BOOL result))completionHandler { NSOperationQueue *current_queue = [NSOperationQueue currentQueue]; // some setup code here NSOperationQueue *q = [[NSOperationQueue alloc] init]; [q addOperationWithBlock:^{ BOOL ok = YES;// some result // do some long running processing here [current_queue addOperationWithBlock:^{ completionHandler(ok); }]; }]; 

Je voulais faire quelques tâches sur une queue et ensuite exécuter un bloc d'achèvement comme mentionné @rmaddy. Je suis tombé sur le Guide de programmation de concurrency d'Apple et mis en œuvre ceci (avec dispatch_retain & dispatch_released commenté parce que j'utilise ARC) – https://developer.apple.com/library/ios/documentation/General/Conceptual/ConcurrencyProgrammingGuide/OperationQueues /OperationQueues.html#//apple_ref/doc/uid/TP40008091-CH102-SW1

 void average_async(int *data, size_t len, dispatch_queue_t queue, void (^block)(int)) { // Retain the queue provided by the user to make // sure it does not disappear before the completion // block can be called. //dispatch_retain(queue); // comment out if use ARC // Do the work on user-provided queue dispatch_async(queue, ^{ int avg = average(data, len); dispatch_async(queue, ^{ block(avg);}); // Release the user-provided queue when done //dispatch_release(queue); // comment out if use ARC }); }