2015-01-21 25 views
6

Mam kilka NSOperation s na wykresie zależność:Jak mogę anulować zależności NSOperation?

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

[op2 addDependency:op1]; 

Oto jak ja ich trwania:

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

Teraz muszę je anulować. W jaki sposób mogę anulować wszystkie NSOperation s na wykresie zależności i czy żadne inne NSOperation s nie zostaną anulowane?


co próbowałem:

Wywołanie cancel po obu NSOperation nie anulować drugi (o ile mogę powiedzieć):

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

Anulowanie kolejkę również anulować operacje, które nie są częścią wykresu zależności od op1 i op2 (jeśli w kolejce są jakieś takie operacje):

[queue cancelAllOperations]; 

Rozwiązałem to za pomocą niestandardowej metody, która rekurencyjnie przegląda zależności między NSOperation i anuluje je. Jednak nie jestem zadowolony z tego rozwiązania, ponieważ czuję, że walczę ramy:

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

Odpowiedz

8

Nie istnieje pojęcie danego NSOperation automatycznie anulowanie jego zależności. Dzieje się tak dlatego, że wiele modeli NSOperation może być zależnych od tego samego innego NSOperation. Zależność istnieje ściśle w celu opóźnienia wykonania określonego NSOperation, dopóki nie zostaną wykonane wszystkie jego zależności.

Można rozważyć napisanie podklasę NSOperation:

@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 

Uwaga: Powyższy kod nie jest gwarantowana być wolna od błędów.

+0

Gotcha, +1. Mogę spróbować upewnić się, że wszystkie 'NSOperation's z tego samego wykresu zależności zostaną dodane do tego samego' NSOperationQueue' (i upewnić się, że nic innego nie jest w tej kolejce), tak żebym mógł po prostu wywołać '[queue cancelAllOperations]'. –

+1

Jeśli utworzyłeś nową 'NSOperationQueue' dla każdej grupy' NSOperation's, które chcesz anulować jednocześnie, możesz użyć właściwości 'underlyingQueue', aby umieścić je w tej samej kolejce systemowej. 'NSOperationQueue' nadal będzie tylko anulować operacje, o których wie, nawet jeśli działa na tym samym' dispatch_queue_t' jak inne. –

+1

Z dokumentacji NSOperationQueue: Anulowanie operacji powoduje, że operacja ignoruje wszelkie zależności, jakie może ona mieć.Takie zachowanie umożliwia kolejce wykonanie metody uruchamiania operacji tak szybko, jak to możliwe. Metoda startowa z kolei przenosi operację do stanu gotowego, aby można ją było usunąć z kolejki. To jednak nie działa. – Brett

1

Brzmi tak, jakbyś próbował pogrupować operacje w tej samej kolejce. Aby to osiągnąć, najlepiej podzielić je za pomocą kolejki w grupie. Tak więc dla każdej grupy utwórz podklasę NSOperation w trybie współbieżnym, dołącz kolejkę, dodaj każdą pod-operację do kolejki. Zastąp anuluj i wywołaj [super anuluj], a następnie [self.queue cancelAllOperations].

Ogromną zaletą tego podejścia jest możliwość ponowienia operacji poprzez ponowne dodanie do pod-kolejki bez wpływu na kolejność głównej kolejki.