2011-09-07 18 views
9

Czy istnieje odpowiednik [NSOperationQueue currentQueue] lub [NSThread currentThread] dla NSOperation?Jak uzyskać dostęp do aktualnie wykonywanej NSOperacji?

Mam dość złożony model domeny, w którym ciężkie przetwarzanie odbywa się dość głęboko w stosie wywołań. Aby anulować operację w odpowiednim czasie, musiałbym przekazać NSOperation jako parametr do każdej metody, aż dojdę do punktu, w którym chcę przerwać dłuższą pętlę. Używając wątków, mógłbym użyć [[NSThread currentThread] isCancelled], więc byłoby to wygodne, gdyby istniał odpowiednik dla NSOperation, niestety jest tylko pozornie bezużyteczny [NSOperationQueue currentQueue].

Odpowiedz

3

To nie jest dobry pomysł. Operacje są zwykle anulowane przez ich kolejkę. W ramach metody main() operacji można okresowo sprawdzać, czy self jest anulowane (powiedzmy, co n przechodzi przez pętlę lub na początku każdego większego bloku poleceń) i przerwać, jeśli tak.

Aby odpowiedzieć na anulowanie (powiedzmy, że jakiś element interfejsu użytkownika związany ze stanem operacji lub kolejki), użyjesz obserwacji wartości klucza (KVO), aby kontroler obserwował operacje "rozpoczęte, ukończone i anulowane właściwości (w razie potrzeby), a następnie ustaw stan interfejsu użytkownika (zawsze w głównym wątku) po zaktualizowaniu kluczy. Zgodnie z uwagami JeremyP, ważne jest, aby zauważyć, że powiadomienia KVO pochodzą z wątku op, a interfejs użytkownika powinien (prawie) zawsze być manipulowany na wątku main, więc będziesz musiał użyć opcji -performSelectorOnMainThread ..., aby zaktualizować rzeczywisty interfejs użytkownika kiedy otrzymasz informację o zmianie stanu KVO o twoich operacjach.

Co tak naprawdę próbujesz zrobić? To znaczy, dlaczego uważasz, że inne części aplikacji muszą wiedzieć bezpośrednio o bieżącej operacji?

+0

-1 obawiam. Nic z tego nie zadziała. Ustawienie właściwości isCancelled operacji nie będzie miało żadnego efektu, chyba że operacja okresowo sprawdza właściwość isCancelled. Z pewnością KVO nie będzie działać, ponieważ powiadomienia KVO są odbierane w tym samym wątku, w którym są wysyłane. – JeremyP

+3

Errr ... Czy przeczytałeś mój post przed głosowaniem w dół? Obserwowanie tych właściwości jest * dokładnie * jak te rzeczy są zrobione. Obserwujesz zmianę stanu, a następnie użyj funkcji -performSelectorOnMainThread ..., aby zrobić wszystko, co trzeba zrobić w głównym wątku. "Nic z tego nie zadziała" to dla mnie nowość, ponieważ mam kilka aplikacji właśnie takich. Ponadto, nigdy nie powiedziałem, że * ustawić * anulowanie. W rzeczywistości powiedziałem, że kolejka anuluje operację, a operacja sprawdza okresowo ten stan i przestaje działać, jeśli jest prawdziwa. –

+0

Co się dzieje: kolejka kasuje ops -> op posty KVO notatka isCancelled, uchwyty się zatrzymują -> Observer (niektórzy kontroler twoich) notatek się zmienia, a jeśli ma do zrobienia, robi to w głównym wątku. Działa za każdym razem. To, że twój kontroler jest przesyłany w innym wątku, nie oznacza, że ​​nie poradzi sobie z tym. Jeśli ma coś zrobić w głównym wątku, idź przed siebie i wyślij coś w głównym wątku. –

0

Skąd wiadomo, którą operację chcesz anulować? Gdy dojdziesz do momentu, w którym chcesz anulować, po prostu wywołaj [operacje myQueue] i przechodź przez operacje, aż znajdziesz te, które chcesz anulować. Domyślam się, że jeśli masz miliony operacji (lub tysiące), to może nie działać.

[Operacje myQueue] jest bezpieczny dla wątków - migawka zawartości kolejki. Możesz nurkować przez to dość szybko anulować w dowolnym momencie.

Inny sposób: NSOperationQueue nie jest singletonem, więc można utworzyć Q, które ma na myśli 200 zadań, a następnie anulować wszystkie 20, po prostu otrzymując Q i anulując je wszystkie. Przechowuj Q w słowniku w głównym wątku, a następnie możesz otrzymać zlecenia, które chcesz anulować z dyktatu i anulować je wszystkie. tzn. masz 1000 rodzajów operacji i w punkcie kodu, w którym zdajesz sobie sprawę, że nie potrzebujesz określonego zadania, po prostu otrzymujesz Q dla tego rodzaju i przeglądaj je, aby anulować zadania.

4

Nie, nie ma metody, aby znaleźć aktualnie wykonywaną operację.

dwa sposoby rozwiązania problemu:

  1. Operacje są obiektami. Jeśli potrzebujesz obiektu A, aby porozmawiać z obiektem B, musisz zaaranżować, aby A miało odniesienie do B. Istnieje wiele sposobów, aby to zrobić. Jednym ze sposobów jest przekazanie operacji do każdego obiektu, który musi o tym wiedzieć. Innym jest użycie delegacji. Trzecim jest uczynienie operacji częścią jakiegoś większego "kontekstu", który jest przekazywany do każdej metody lub funkcji. Jeśli okaże się, że musisz przekazać referencję z jednego obiektu do kilku innych tylko po to, aby dostać się do obiektu, który w końcu go użyje, jest to wskazówka, że ​​powinieneś pomyśleć o przestawieniu kodu.

  2. Metoda "podnoszenia ciężkiego" zwraca pewną wartość, która jest przekazywana do łańcucha połączeń. Niekoniecznie potrzebujesz metody podnoszenia ciężarów, aby zadzwonić pod numer [currentOperation cancel], aby osiągnąć swój cel. W rzeczywistości lepiej byłoby, gdyby zwrócił pewną wartość, którą operacja zrozumie, oznaczającą "praca została zakończona, zatrzymaj się teraz", ponieważ może sprawdzić wartość zwrotu i natychmiast wyjść, zamiast dzwonić pod numer -isCancelled raz na jakiś czas, aby znaleźć czy zostało anulowane.

1

Można zapisać bieżącą operację w słowniku słownika. Tylko pamiętaj, aby się go pozbyć przed wyjściem. Możesz bezpiecznie użyć dyktatu wątku, jeśli utworzyłeś obiekt.

4

wpadł na przedłużenie w Swift zwracającej operacji uruchomione

extension NSOperationQueue { 
    public var runningOperations: [NSOperation] { 
     return operations.filter {$0.executing && !$0.finished && !$0.cancelled} 
    } 
} 

Następnie można odebrać pierwszy

if let operation = aQueue.runningOperations.first {} 
+0

Sneaky, ale spróbowałem i działa całkiem elegancko, włączając w to klasy od deklaracji Swift do wywołania w Objective-C za pomocą [[[NSOperationQueue currentQueue] runningOperations] objectAtIndex: 0]. – eGanges

1

Można użyć kombinacji [NSOperationQueue currentQueue] & [ NSThread currentThread], aby to osiągnąć.

Zasadniczo należy wykonać pętlę w operacjach na bieżącej kwerendzie i znaleźć operację działającą na bieżącej operacji.

NSOperation nie zapewnia dostępu do wątku, który jest uruchomiony, więc musisz dodać tę własność samodzielnie i ją przypisać.

Pewnie już instacji NSOperation i zapewnienie głównym, więc dodać „wątek” własności do tej podklasy:

@interface MyOperation : NSOperation 
    @property(nonatomic,strong) NSThread *thread ; 
@end 

Następnie w „głównym” przypisać bieżącego wątku do tej nieruchomości

myOperation.thread = [NSThread currentThread] 

następnie można dodać 'currentOperation' metodę:

+(MyOperation *)currentOperation 
{ 
    NSOperationQueue *opQueue = [NSOperationQueue currentQueue] ; 
    NSThread *currentThread = [NSThread currentThread] ; 

    for(MyOperation *op in opQueue.operations) { 
     if([op isExecuting] && [op respondsToSelector:@selector(thread)]) { 
       if(op.thread == currentThread) { 
        return (op) ; 
       } 
      } 
     } 
    } 

    return nil ; 
} 
Powiązane problemy