2010-09-03 24 views
1

J'ai créé un NSOperation dans la file d'attente comme ceci:Problèmes avec NSOperationQueue et dealloc appelés et s'écraser App

ImageLoadingOperation *operation = [[ImageLoadingOperation alloc] initWithImageURL:url target:self action:@selector(didFinishLoadingImageWithResult:)]; 
[operationQueue addOperation:operation]; 
[operation release]; 

Et cela fonctionne très bien, mais si la vue se surgit avant que l'opération se termine l'application se bloque avec "EXC_BAD_ACCESS"

J'ai essayé d'annuler la file d'attente de l'opération en appelant cancelAllOperations mais étant donné qu'elle est déjà en cours, elle n'empêche pas l'application de se bloquer. Les docos disent que si l'opération est en cours, il appartient à l'opération de détecter qu'elle a été annulée et de répondre de façon appropriée, mais pas trop sûr de la façon dont je mettrais en œuvre cela?

Des idées?

+0

Ainsi, operationQueue appartient à la vue et la file d'attente est libérée avec la vue? –

+0

J'ai essayé d'arrêter la file d'attente d'opération avant que la file d'attente et la vue soient libérées mais sans succès – Rudiger

Répondre

1

Il s'agit d'un problème général pour View appelant un réseau puis un rappel.

Ma solution est que vous pouvez conserver la vue avant d'appeler l'opération. Et puis, lorsque l'opération se termine, vous libérez la vue.

- (void)longTask { 
    [self retain]; 
} 

- (void)longTaskDidFinish { 
    // do something if you want 
    [self release]; 
} 
+0

Si facile et fonctionne un charme. Merci beaucoup – Rudiger

0

Vous devrez soit remplacer l'opération « annuler » dans votre classe ImageLoadingOperation, ou que votre ImageLoadingOperation s'ajouter en tant qu'observateur KVO à la propriété « annulé ». Là - vous pouvez annuler votre opération de manière intelligente de telle sorte qu'elle ne se bloque pas. En outre, si votre ImageLoadingOperation s'exécute en arrière-plan, il serait plus judicieux de différer votre accès aux vues en quelque sorte au thread principal (où tout le dessin a lieu). Vous pouvez utiliser un dispatch_sync (dispatch_get_main_queue(),^{}); ou même effectSelectorOnMainThread pour un accès réel à la vue associée. Vous voyez - l'intérêt d'utiliser une file d'attente d'opérations est de supprimer les dépendances et de laisser les choses s'exécuter en parallèle, mais votre opération doit se synchroniser avec les changements du système de vue et être conçue pour être complète et robuste.

0

Vous pouvez conserver la vue avant l'appel du rappel d'opération, comme vodkhang mentionné ci-dessus. Mais cela prolongera inutilement la durée de vie de la vue car, puisque la vue est sautée, vous ne voulez plus que l'opération continue.
Voici un croquis de ce que vous devez faire pour répondre à la commande d'annulation:

- (void)start{ 
    if(self.isCancelled){ 
     [self markAsFinished]; 
     return; 
    } 
    //start your task asynchronously 
} 


//If you want to cancel the downloading progress immediately, implement your own 'cancel' method 
- (void)cancel{ 
    [super cancel]; 
    if(self.isExecuting){ 
     { 
      ...... 
      cancel load process 
      ...... 
     } 
     [self markAsFinished]; 
    } 
} 

- (void)markAsFinished{ 
    ...... 
    change 'finished' to YES' generate KVO notifications on this key path 
    change 'executing' to 'YES'; generate KVO notification on this key path 
    ...... 
} 

Cette esquisse est basée sur la bibliothèque réseau ASIHTTPRequest et il y a un official guide sur la façon dont vous devez répondre à la commande annuler.