Pouvez-vous utiliser annuler/isCancelled avec GCD/dispatch_async?

Je me demandais, vous pouvez utiliser annuler/cancelAllOperations/.isCancelled avec un sujet que vous avez lancé avec PGCD?

Actuellement, je viens d'utiliser un booléen comme un drapeau, d'annuler le processus en arrière-plan.

Disons que vous voulez faire beaucoup de traitement en arrière-plan, tout en gardant l'INTERFACE utilisateur réactive, de sorte que vous pouvez attraper un bouton annuler (ou animer quelque chose pour montrer que le processeur travaille). Voici comment nous le faisons...

@interface AstoundingView : UIView
{
BOOL    pleaseAbandonYourEfforts;
blah
}
@implementation AstoundingView
//
//these are the foreground routines...
//begin, abandon and all-done
//
-(void)userHasClickedToBuildASpaceship
{
[YourUIStateMachine buildShip];
[self procedurallyBuildEnormousSpaceship];
}
-(void)userHasClickedToAbandonBuildingTheSpaceship
{
[YourUIStateMachine inbetween];
pleaseAbandonYourEfforts = false; //that's it!
}
-(void)attentionBGIsAllDone
{
//you get here when the process finishes, whether by completion
//or if we have asked it to cancel itself.
[self typically setNeedsDisplay, etc];
[YourUIStateMachine nothinghappening];
}
//
//these are the background routines...
//the kickoff, the wrapper, and the guts
//
//The wrapper MUST contain a "we've finished" message to home
//The guts can contain messages to home (eg, progress messages)
//
-(void)procedurallyBuildEnormousSpaceship
{
//user has clicked button to build new spaceship
pleaseAbandonYourEfforts = FALSE;
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0),
^{ [self actuallyProcedurallyBuildInBackground]; }
);
//as an aside, it's worth noting that this does not work if you
//use the main Q rather than a global Q as shown.
//Thus, this would not work:
//dispatch_async(dispatch_get_main_queue(), ^{ ...; });
}
-(void)actuallyProcedurallyBuildInBackground
{
//we are actually in the BG here...
[self setUpHere];
//set up any variables, contexts etc you need right here
//DO NOT open any variables, contexts etc in "buildGuts"
//when you return back here after buildGuts, CLEAN UP those
//variables, contexts etc at this level.
//(using this system, you can nest as deep as you want, and the
//one CHECKER pseudocall will always take you right out.
//You can insert CHECKERs anywhere you want.)
[self buildGuts];
//Note that any time 'CHECKER' "goes off', you must fall-
//through to exactly here.  This is the common fall-through point.
//So we must now tidy-up, to match setUpHere.
[self wrapUpHere];
//when you get to here, we have finished (or, the user has cancelled
//the background operation)
//Whatever technique you use,
//MAKE SURE you clean up all your variables/contexts/etc before
//abandoning the BG process.
//and then you must do this......
//we have finished. it's critical to let the foreground know NOW,
//or else it will sit there for about 4 to 6 seconds (on 4.3/4.2)
//doing nothing until it realises you are done
dispatch_sync(
dispatch_get_main_queue(),
^{[self attentionBGIsAllDone];} //would setneedsdisplay, etc
);
return;
}
-(void)buildGuts
{
//we are actually in the BG here...
//Don't open any local variables in here.
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
//to get stuff done from time to time on the UI, something like...
CHECKER
dispatch_sync(
dispatch_get_main_queue(),
^{[supportStuff pleasePostMidwayImage:
[UIImage imageWithCGImage:halfOfShip] ];}
);
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
for ( i = 1 to 10^9 )
{
CHECKER
[self blah blah];
}
CHECKER
[self blah blah];
CHECKER
[self blah blah];
CHECKER
[self blah blah];
return;
}

et le VÉRIFICATEUR ne fait rien de plus que de vérifier le drapeau est vrai...

#define CHECKER if ( pleaseAbandonYourEfforts == YES ) \
{NSLog(@"Amazing Interruption System Working!");return;}

Tout cela fonctionne parfaitement.

Mais ........ est-il possible d'utiliser annuler/cancelAllOperations/.isCancelled avec ce type d'utilisation de PGCD?

Quelle est l'histoire ici? Des acclamations.


PS - pour tout les débutants à l'aide de ce "six la partie" modèle d'arrière-plan.

Noter que, comme BJ faits saillants ci-dessous, chaque fois que vous briser le processus de bg...

vous devez nettoyer toutes les variables que vous avez ouvert!

Dans mon idiome, vous devez allouer tous les variable, de contextes, de la mémoire, etc, plus précisément dans "setUpHere". Et vous devez les libérer dans "wrapUpHere". (Cet idiome continue de travailler si vous allez plus loin et plus profond, tandis que dans le BG.)

Alternativement, faire exactement ce que BJ montre dans son exemple. (Si vous utilisez BJ méthode, être prudent, si vous allez plus loin.)

Quelle que soit la méthode que vous utilisez, vous devez nettoyer toutes les variables/contextes/mémoire que vous avez ouvert, lorsque vous briser le processus de BG. Espérons que cela aide quelqu'un, un jour!

Je crois que vous avez manqué mon point sur le seul point de retour. Si vous allouer les objets temporaires dans la buildGuts méthode, vous devez vous assurer de les relâcher dans la méthode, avant de sortir de la méthode et de perdre le pointeur à ces objets.
J'ai ajouté une autre mise à jour de clarification dans ma déclaration sur le seul point de retour. Votre [self quickly wrap up in a bow] appeler pas de gérer toute la gestion de la mémoire qui peut être nécessaire, et tout simplement s'assurer qu'une certaine méthode sera exécutée après la buildGuts méthode ne permet pas de le résoudre. Quand je me réfère à un seul point de retour, je voulais dire qu'il n'y a qu'un seul endroit où la méthode de sortie. En vertu de votre mise en œuvre, il peut sortir de n'importe où le CHECKER macro est utilisée. Ce n'est pas un seul point de retour.
Salut BJ, j'ai ajouté quelques commentaires expliquant simplement que dans l'exemple de code, cheers!
Juste pour être ultra clair, comme il est dit "// Ne pas ouvrir les variables locales de ici." .. c'est la fin de celui-ci et la plupart de très bonne façon d'éviter d'ouvrir des variables dans les il y! heh.
Un peu en retard pour la fête mais pleaaase, ne pas utiliser l'auto à l'intérieur du PGCD de bloc, cela va créer un cycle de conserver et de rendre votre vue sera conservé pour toujours.... utiliser un __faibles pointeur pour accéder à la place de la variable... salutations

OriginalL'auteur Fattie | 2011-03-27