2015-01-21 6 views
6

Ich habe einige NSOperation s in einem Abhängigkeitsgraphen:Wie storniere ich die Abhängigkeiten einer NSOperation?

NSOperation *op1 = ...; 
NSOperation *op2 = ...; 

[op2 addDependency:op1]; 

Hier ist, wie ich sie renne:

NSOperationQueue *queue = [[NSOperationQueue alloc] init]; 
[queue addOperation:op1]; 
[queue addOperation:op2]; 

Jetzt muss ich sie abzubrechen. Wie stelle ich sicher, dass alle NSOperation s in einem Abhängigkeitsdiagramm abgebrochen werden und keine anderen NSOperation s abgebrochen werden?


was ich versucht habe:

Aufruf cancel auf beiden NSOperation nicht kündigen das andere nicht (soweit ich das beurteilen kann):

[op1 cancel]; // doesn't cancel op2 
// -- or -- 
[op2 cancel]; // doesn't cancel op1 

die Warteschlange abbrechen würde abbrechen auch Operationen, die nicht Teil des Abhängigkeitsdiagramms von op1 und op2 sind (wenn sich solche Operationen in der Warteschlange befinden):

[queue cancelAllOperations]; 

Also löste ich dies mit einer benutzerdefinierten Methode, die rekursiv durch eine NSOperation Abhängigkeiten sieht und löscht sie. Allerdings bin ich mit dieser Lösung nicht zufrieden, denn ich fühle mich wie ich den Rahmen bin kämpfen:

- (void)recursiveCancel:(NSOperation *)op 
{ 
    [op cancel]; 
    for (NSOperation *dep in op.dependencies) 
    { 
     [self recursiveCancel:op]; 
    } 
} 

Antwort

8

Es hat keinen Begriff eines NSOperation automatisch seine Abhängigkeiten Cancelling nicht vorhanden ist. Dies liegt daran, dass mehrere NSOperation s von denselben anderen NSOperation abhängig sein können. Die Abhängigkeitsbeziehung existiert ausschließlich, um die Ausführung einer bestimmten NSOperation zu verzögern, bis alle ihre Abhängigkeit NSOperation s abgeschlossen sind.

Sie können prüfen, eine Unterklasse von NSOperation schreiben:

@interface NSOperationOneToOne : NSOperation 
- (void)addOneToOneDependency:(NSOperation *)operation; 
- (void)removeOneToOneDependency:(NSOperation *)operation; 
@end 

@implementation NSOperationOneToOne { 
    NSMutableArray *oneToOneDependencies; 
} 
- (void)addOneToOneDependency:(NSOperation *)operation { 
    [oneToOneDependencies addObject:operation]; 
    [self addDependency:operation]; 
} 
- (void)removeOneToOneDependency:(NSOperation *)operation { 
    [oneToOneDependencies removeObject:operation]; 
    [self removeDependency:operation]; 
} 
- (void)cancel { 
    [super cancel]; 
    [oneToOneDependencies makeObjectsPerformSelector:@selector(cancel)]; 
} 
@end 

Hinweis: Der obige Code ist nicht als fehlerfrei gewährleistet.

+0

Gotcha, +1. Ich könnte versuchen, sicherzustellen, dass alle 'NSOperation' aus dem gleichen Abhängigkeitsgraphen zur selben' NSOperationQueue' hinzugefügt werden (und sicherstellen, dass sich nichts anderes in dieser Warteschlange befindet), so dass ich einfach '[queue cancelAllOperations]' aufrufen kann. –

+1

Wenn Sie eine neue 'NSOperationQueue' für jede Gruppe von' NSOperation' erstellt haben, die Sie sofort abbrechen möchten, können Sie sie mit der 'basicingQueue' -Eigenschaft in dieselbe Systemwarteschlange stellen. Die 'NSOperationQueue' wird immernoch nur die Operationen abbrechen, die sie kennt, selbst wenn sie auf der selben' dispatch_queue_t' läuft wie eine andere. –

+1

Aus der NSOperationQueue-Dokumentation: Durch das Abbrechen einer Operation ignoriert die Operation etwaige Abhängigkeiten.Dieses Verhalten ermöglicht es der Warteschlange, die Startmethode des Vorgangs so schnell wie möglich auszuführen. Die Startmethode wiederum verschiebt die Operation in den fertigen Zustand, sodass sie aus der Warteschlange entfernt werden kann. Dies scheint jedoch nicht zu funktionieren. – Brett

1

Klingt so, als ob Sie versuchen, Operationen in derselben Warteschlange zu gruppieren. Um dies zu erreichen, ist es am besten, sie über eine Warteschlange pro Gruppe aufzuteilen. Erstellen Sie für jede Gruppe eine NSOperation-Unterklasse im gleichzeitigen Modus, fügen Sie eine Warteschlange hinzu und fügen Sie jede Unteroperation der Warteschlange hinzu. Überschreiben Sie den Abbruch und rufen Sie [Super Cancel] und dann [self.queue cancelAllOperations] auf.

Ein großer Vorteil dieses Ansatzes besteht darin, dass Sie Operationen wiederholen können, indem Sie erneut zur Unterwarteschlange hinzufügen, ohne die Reihenfolge der Hauptwarteschlange zu beeinflussen.

Verwandte Themen