2009-11-20 3 views
0

J'utilise une sous-classe de NSOperation pour faire des processus d'arrière-plan. Je veux que l'opération soit annulée lorsque l'utilisateur clique sur un bouton.iPhone - retour d'un NSOperation

Voici ce que ma sous-classe NSOperation ressemble

- (id)init{ 
    self = [super init]; 
    if(self){ 
     //initialization code goes here 
     _isFinished = NO; 
     _isExecuting = NO; 
    } 

    return self; 
} 

- (void)start 
{ 
    if (![NSThread isMainThread]) 
    { 
     [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO]; 
     return; 
    } 
    [self willChangeValueForKey:@"isExecuting"]; 
    _isExecuting = YES; 
    [self didChangeValueForKey:@"isExecuting"]; 

    //operation goes here 
} 

- (void)finish{ 
    //releasing objects here 

    [self willChangeValueForKey:@"isExecuting"]; 
    [self willChangeValueForKey:@"isFinished"]; 

    _isExecuting = NO; 
    _isFinished = YES; 

    [self didChangeValueForKey:@"isExecuting"]; 
    [self didChangeValueForKey:@"isFinished"]; 
} 

- (void)cancel{ 
    [self willChangeValueForKey:@"isCancelled"]; 

    [self didChangeValueForKey:@"isCancelled"]; 
    [self finish]; 
} 

Et voilà comment je suis d'ajouter des objets de cette classe à une file d'attente et d'écoute pour les notifications KVO

operationQueue [INIT [NSOperationQueue alloc]] = ; [operationQueue setMaxConcurrentOperationCount: 5]; [operationQueue addObserver: self forKeyPath: @ "opérations" options: 0 contexte: & OperationsChangedContext];

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context 
{ 
    if (context == &OperationsChangedContext) { 
     NSLog(@"Queue size: %u", [[operationQueue operations] count]); 
    } 
    else { 
     [super observeValueForKeyPath:keyPath ofObject:object change:change context:context]; 
    } 
} 

Pour annuler une opération (sur un clic, par exemple, le bouton), j'ai essayé d'appeler -cancel mais il ne fait pas de différence. Également essayé d'appeler -finish mais même cela ne change rien.

Chaque fois que j'ajoute une opération à la file d'attente, la taille de la file d'attente augmente seulement. finish est appelé (vérifié à l'aide des instructions NSLog) mais il ne termine pas vraiment l'opération. Je ne suis toujours pas très confiant que je fais ça correctement

Quelqu'un peut-il me dire où je vais mal?

Merci beaucoup

Répondre

2

De l'NSOperation Class Reference:

Annulation d'une opération ne force pas immédiatement pour arrêter ce qu'il fait. Bien que le respect de la valeur renvoyée par isCancelled soit prévu pour toutes les opérations, votre code doit explicitement vérifier la valeur retournée par cette méthode et annuler au besoin.

En d'autres termes, la méthode cancel n'annule pas réellement l'opération à moins que votre implémentation ne l'impose. Encore une fois, de la section pertinente:

- (void)cancel

Cette méthode ne force pas votre code d'opération pour arrêter. Au lieu de cela, il met à jour les indicateurs internes de l'objet pour refléter le changement d'état.

+0

Oui, lisez ceci. Mais où puis-je vérifier isCancelled? Vous ne pouvez pas déclencher une minuterie dans un NSOperation! – lostInTransit

+0

Vous n'auriez sûrement pas besoin d'interroger le changement de drapeau, vous devrez simplement exécuter votre procédure d'annulation à partir de la méthode cancel quand elle sera appelée? – jnic

+0

S'il vous plaît, supportez-moi ici.J'appelle la méthode de jeu d'un AVAudioPlayer dans la classe NSOperation. Dans la méthode d'annulation, j'arrête le joueur, mais que faire ensuite? Le nombre d'opérations dans la file d'attente apparaît toujours le même. – lostInTransit

0

Vous avez juste besoin les éléments suivants pour y parvenir:

Dans votre sous-classe NSOperation, ajouter à la méthode principale

while (! self.isCancelled) { 
    [NSThread sleepForTimeInterval:1]; 
} 

Dans la classe GUI, vous avez besoin d'une variable d'instance à votre sous-classe NSOperation, et dans la méthode qui gère le bouton, vous annulez votre sous-classe NSOperation. Par exemple:

- (IBAction) clickButton: (UIBarButtonItem *) item{ 
[myOperation cancel]; 
} 
+0

pourquoi voter vers le bas? Vos threads ne devraient-ils pas courir en boucle? – yano

Questions connexes