Ok, donc si je comprends bien, vous avez deux questions :
-
Avez-vous besoin de la performSelectorOnMainThread:
qui apparaît dans les commentaires de votre code ? Que fait ce code ?
-
Pourquoi le _isCancelled
n'est pas modifié lorsque vous appelez cancelAllOperations
sur le NSOperationQueue
qui contient cette opération ?
Traitons-les dans l'ordre. Je vais supposer que votre sous-classe de NSOperation
s'appelle MyOperation
juste pour faciliter l'explication. Je vais expliquer ce que vous comprenez mal, puis donner un exemple corrigé.
1. Exécution simultanée de NSOpérations
La plupart du temps, vous utiliserez NSOperation
avec un NSOperationQueue
et d'après votre code, il semble que c'est ce que vous faites. Dans ce cas, votre MyOperation
sera toujours exécuté sur un thread d'arrière-plan, indépendamment de ce que l'on attend de l'utilisateur. -(BOOL)isConcurrent
retourne, puisque la méthode NSOperationQueue
sont explicitement conçus pour exécuter des opérations en arrière-plan.
Ainsi, il n'est généralement pas nécessaire de remplacer l'option -[NSOperation start]
puisque, par défaut, elle invoque simplement la méthode -main
méthode. C'est cette méthode que vous devez surcharger. La méthode par défaut -start
gère déjà la mise en place de la méthode isExecuting
y isFinished
pour vous aux moments opportuns.
Donc si vous voulez un NSOperation
pour qu'il fonctionne en arrière-plan, il suffit de remplacer l'option -main
et le placer sur un NSOperationQueue
.
En performSelectorOnMainThread:
dans votre code entraînerait chaque instance de MyOperation
pour qu'il effectue toujours sa tâche sur le thread principal. Puisqu'un seul morceau de code peut être exécuté sur un thread à la fois, cela signifie qu'aucun autre thread ne peut être exécuté. MyOperation
pourraient fonctionner. Le but de NSOperation
y NSOperationQueue
est de faire quelque chose en arrière-plan.
Le seul moment où vous voulez forcer les choses sur le thread principal est lorsque vous mettez à jour l'interface utilisateur. Si vous avez besoin de mettre à jour l'interface utilisateur lorsque votre programme MyOperation
finitions, que c'est quand vous devez utiliser performSelectorOnMainThread:
. Je vais vous montrer comment faire dans mon exemple ci-dessous.
2. Annulation d'une opération d'ONS
-[NSOperationQueue cancelAllOperations]
appelle le -[NSOperation cancel]
ce qui entraîne des appels ultérieurs à la méthode -[NSOperation isCancelled]
pour revenir YES
. Cependant vous avez fait deux choses pour rendre cela inefficace.
-
Vous utilisez @synthesize isCancelled
pour remplacer l'option de la NSOperation -isCancelled
méthode. Il n'y a aucune raison de le faire. NSOperation
met déjà en œuvre -isCancelled
d'une manière parfaitement acceptable.
-
Vous vérifiez votre propre _isCancelled
pour déterminer si l'opération a été annulée. NSOperation
garantit que [self isCancelled]
retournera YES
si l'opération a été annulée. Il fait pas ne garantit pas que votre méthode setter personnalisée sera appelée, ni que votre propre variable d'instance est à jour. Vous devez vérifier [self isCancelled]
Ce que vous devriez faire
L'en-tête :
// MyOperation.h
@interface MyOperation : NSOperation {
}
@end
Et la mise en œuvre :
// MyOperation.m
@implementation MyOperation
- (void)main {
if ([self isCancelled]) {
NSLog(@"** operation cancelled **");
}
// Do some work here
NSLog(@"Working... working....")
if ([self isCancelled]) {
NSLog(@"** operation cancelled **");
}
// Do any clean-up work here...
// If you need to update some UI when the operation is complete, do this:
[self performSelectorOnMainThread:@selector(updateButton) withObject:nil waitUntilDone:NO];
NSLog(@"Operation finished");
}
- (void)updateButton {
// Update the button here
}
@end
Notez que vous n'avez pas besoin de faire quoi que ce soit avec isExecuting
, isCancelled
ou isFinished
. Tout cela est géré automatiquement pour vous. Il suffit de remplacer le -main
méthode. C'est aussi simple que cela.
(Note : techniquement, ce n'est pas un "concurrent". NSOperation
dans le sens où -[MyOperation isConcurrent]
rendrait NO
tel que mis en œuvre ci-dessus. Cependant, il se être exécuté sur un fil d'arrière-plan. Le site isConcurrent
devrait vraiment s'appeler -willCreateOwnThread
car c'est une description plus précise de l'intention de la méthode).