Frage

Ich bin nicht in der Lage eine gute Dokumentation darüber zu finden, wie NSOperation Unterklasse gleichzeitig zu sein und auch Unterstützung Stornierung. Ich lese die Apple-docs, aber ich bin nicht in der Lage ein „offizielles“ Beispiel zu finden.

Hier ist mein Quellcode:

@synthesize isExecuting = _isExecuting;
@synthesize isFinished = _isFinished;
@synthesize isCancelled = _isCancelled;

- (BOOL)isConcurrent
{
    return YES;
}

- (void)start
{
/* WHY SHOULD I PUT THIS ?
    if (![NSThread isMainThread])
    {
        [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
        return;
    }
*/

    [self willChangeValueForKey:@"isExecuting"];
    _isExecuting = YES;
    [self didChangeValueForKey:@"isExecuting"];


    if (_isCancelled == YES)
    {
        NSLog(@"** OPERATION CANCELED **");
    }
    else
    {
        NSLog(@"Operation started.");
        sleep(1);
        [self finish];
    }
}

- (void)finish
{
    NSLog(@"operationfinished.");

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

    _isExecuting = NO;
    _isFinished = YES;

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

    if (_isCancelled == YES)
    {
        NSLog(@"** OPERATION CANCELED **");
    }
}

Im Beispiel fand ich, ich verstehe nicht, warum performSelectorOnMainThread: verwendet wird. Es wäre mir eine Operation verhindern, gleichzeitig ausgeführt werden.

Auch wenn ich diese Zeile auf Kommentar, erhalte ich meine Operationen gleichzeitig ausgeführt werden. Allerdings ist die isCancelled Flagge nicht geändert, obwohl ich cancelAllOperations genannt haben.

War es hilfreich?

Lösung

Okay, so wie ich es verstehe, haben Sie zwei Fragen:

  1. Sie benötigen das performSelectorOnMainThread: Segment, das erscheint in den Kommentaren im Code? Was bedeutet, dass Code tun?

  2. Warum ist die _isCancelled Flag wird nicht geändert, wenn Sie cancelAllOperations auf der NSOperationQueue aufrufen, die diese Operation enthält?

Lassen Sie uns beschäftigen sich mit diesen um. Ich gehe davon aus, dass Ihre Unterklasse von NSOperation MyOperation genannt wird, nur für eine einfache Erklärung. Ich werde erklären, was Sie Missverständnisse und dann ein korrigiertes Beispiel.

1. Lauf NSOperations gleichzeitig

Die meiste Zeit werden Sie NSOperations mit einem NSOperationQueue zu verwenden, und aus dem Code, es klingt wie das ist, was du tust. In diesem Fall wird Ihr MyOperation immer auf einem Hintergrund-Thread ausgeführt werden, unabhängig davon, was die -(BOOL)isConcurrent Methode zurückgibt, wird seit NSOperationQueues explizit im Hintergrund laufen Operationen ausgelegt.

Als solches Sie im Allgemeinen nicht brauchen die -[NSOperation start] Methode außer Kraft zu setzen, da standardmäßig einfach die -main Methode aufruft. Das ist die Methode, die Sie überschreiben werden soll. Die Standard -start Methode bereits Griffe isExecuting und isFinished für Sie zu den entsprechenden Zeiten einstellen.

Wenn Sie also ein NSOperation wollen im Hintergrund laufen zu lassen, einfach die -main Methode außer Kraft setzen und es auf einem NSOperationQueue setzen.

Die performSelectorOnMainThread: im Code würde jede Instanz MyOperation verursachen immer seine Aufgabe auf dem Haupt-Thread ausführen. Da nur ein Stück Code kann zu einem Zeitpunkt auf einem Thread ausgeführt werden, bedeutet dies, dass keine andere MyOperations ausgeführt werden können. Der ganze Zweck der NSOperation und NSOperationQueue ist etwas im Hintergrund zu tun.

Das einzige Mal, wenn Sie die Dinge auf den Hauptthread zwingen wollen, ist, wenn Sie die Benutzeroberfläche sind zu aktualisieren. Wenn Sie die Benutzeroberfläche zu aktualisieren, wenn Ihre MyOperation beendet, , die ist, wenn Sie performSelectorOnMainThread: verwenden sollten. Ich werde zeigen, wie das unten in meinem Beispiel zu tun.

2. ein Abbrechen NSOperation

-[NSOperationQueue cancelAllOperations] ruft die -[NSOperation cancel] Methode, die nachfolgenden Aufrufe -[NSOperation isCancelled] auf Rückkehr YES verursacht. Doch , haben Sie zwei Dinge tun dies unwirksam zu machen.

  1. Sie verwenden @synthesize isCancelled NSOperation der -isCancelled Methode außer Kraft zu setzen. Es gibt keinen Grund, dies zu tun. NSOperation bereits implementiert -isCancelled in einer durchaus akzeptabel Weise.

  2. Sie Ihr eigenes _isCancelled Instanz-Variable überprüft, um festzustellen, ob der Vorgang abgebrochen wurde. NSOperation garantiert, dass [self isCancelled] YES zurück, wenn der Vorgang abgebrochen wurde. Es tut nicht Garantie, dass Ihre individuelle Setter-Methode aufgerufen wird, noch, dass die eigene Instanz-Variable ist aktuell. Sie sollten [self isCancelled]

  3. checken

Was Sie tun sollten

Der Header:

// MyOperation.h
@interface MyOperation : NSOperation {
}
@end

Und die Umsetzung:

// MyOperation.m
@implementation MyOperation

- (void)main {
    if ([self isCancelled]) {
        NSLog(@"** operation cancelled **");
    }

    // Do some work here
    NSLog(@"Working... working....")

    if ([self isCancelled]) {
        NSLog(@"** operation cancelled **");
    }
    // Do any clean-up work here...

    // If you need to update some UI when the operation is complete, do this:
    [self performSelectorOnMainThread:@selector(updateButton) withObject:nil waitUntilDone:NO];

    NSLog(@"Operation finished");
}

- (void)updateButton {
    // Update the button here
}
@end

Beachten Sie, dass Sie nichts tun müssen, um mit isExecuting, isCancelled oder isFinished. Das ist alles automatisch für Sie behandelt. außer Kraft setzen Sie einfach die -main Methode. Es ist so einfach.

(Eine Anmerkung:. Technisch ist dies keine „concurrent“ NSOperation, in dem Sinne, dass -[MyOperation isConcurrent] NO wie oben umgesetzt zurückkehren würde es aber wird auf einem Hintergrund-Thread ausgeführt werden, um die isConcurrent. Methode wirklich -willCreateOwnThread benannt werden soll, als dass eine genauere Beschreibung der Absicht des Verfahrens ist.)

Andere Tipps

Die ausgezeichnete Antwort von @BJHomer verdient ein Update.

Concurrent Operationen sollten die start Methode statt main außer Kraft setzen.

Wie bereits erwähnt in der Apple-Dokumentation :

Wenn Sie eine gleichzeitige Operation erstellen, müssen Sie die folgenden Methoden und Eigenschaften auf einem Minimum außer Kraft zu setzen:

  • start
  • asynchronous
  • executing
  • finished

Eine ordnungsgemäße Umsetzung auch erfordert cancel auch außer Kraft zu setzen. Erstellen einer Unterklasse thread-safe und die erforderlichen Semantik richtig hinzubekommen ist auch ziemlich schwierig.

So habe ich lege eine vollständige und Arbeitsunterklasse als Vorschlag in Swift implementiert in Code Review. Kommentare und Anregungen sind willkommen.

Diese Klasse kann leicht als Basisklasse für benutzerdefinierte Operation Klasse verwendet werden.

Ich weiß, das ist eine alte Frage, aber ich habe diese untersucht, in letzter Zeit und die gleichen Beispiele und hatte die gleichen Bedenken begegnet.

Wenn Sie Ihre Arbeit kann innerhalb des Hauptverfahrens synchron ausgeführt werden, müssen Sie nicht einen gleichzeitigen Betrieb benötigen, weder ein Start überschreiben, tun nur Ihre Arbeit und Rückkehr aus dem Haupt wenn Sie fertig sind.

Allerdings, wenn Ihre Arbeitsbelastung von Natur aus asynchron ist - das heißt eine NSURLConnection geladen haben, müssen Sie Unterklasse starten. Wenn Ihre Start-Methode zurückgibt, wird der Vorgang noch nicht abgeschlossen. Es wird nur durch die NSOperationQueue abgeschlossen betrachtet werden, wenn Sie manuell KVO Benachrichtigungen an der isfinished und isExecuting Flags (zum Beispiel einmal die async URL Laden beendet oder nicht).

senden

Schließlich könnte man auf den Hauptthread zum Versand gestartet werden soll, wenn die Async Workload Sie einen Laufschleife hören auf dem Hauptthread erfordern beginnen soll. Da die Arbeit selbst asynchron ist, wird sie Ihre Gleichzeitigkeit nicht beschränken, sondern die Arbeit in einem Arbeitsthread beginnen könnte keine richtige Runloop bereit hat.

Hier finden Sie aktuelle ASIHTTPRequest . Es ist eine HTTP-Wrapper-Klasse auf den NSOperation als Unterklasse gebaut und scheint diese zu implementieren. Beachten Sie, dass ab Mitte 2011 empfiehlt der Entwickler mit ASI nicht für neue Projekte.

In Bezug auf definieren " gelöscht " Eigenschaft (oder definieren " _cancelled " Ivar) innerhalb NSOperation Unterklasse, in der Regel, die nicht notwendig ist. Ganz einfach, weil, wenn USER die Aufhebung auslöst, sollte benutzerdefinierter Code immer benachrichtigt KVO Beobachter, dass Ihr Betrieb jetzt ist beendet mit seiner Arbeit. Mit anderen Worten: isCancelled => isfinished.

Insbesondere dann, wenn NSOperation Objekt auf dem Abschluss anderen Betrieb Objekte abhängig ist, überwacht er den isfinished Schlüsselpfad für diese Objekte. Abschluss und Meldung erzeugen Failing ( im Fall einer Stornierung geschieht ) kann daher die Ausführung anderer Operationen in der Anwendung verhindern.


BTW, @BJ Homers Antwort: "Die isConcurrent Methode sollte wirklich genannt -willCreateOwnThread sein" macht viel Sinn !

Weil, wenn Sie NICHT Start-Methode tun außer Kraft setzen, einfach manuell aufrufen NSOperation-Object-Standard-Start-Methode, Aufruf-Thread selbst ist, standardmäßig synchron; so, NSOperation-Objekt ist nur ein nicht-gleichzeitiger Betrieb.

Wenn Sie jedoch überschreiben Start-Methode DO, innerhalb Start-Methode Implementierung, benutzerdefinierten Code sollte einen separaten Thread laichen ... etc, dann brechen Sie erfolgreich die Einschränkung von „Aufruf-Thread-Standard Wesen synchron“, also ein gleichzeitiger-Betrieb immer, NSOperation-Objekt macht es asynchron danach ausgeführt werden kann.

Dieser Blog-Eintrag:

http://www.dribin.org/dave / Blog / Archiv / 2009/09/13 / snowy_concurrent_operations /

erklärt, warum Sie benötigen:

if (![NSThread isMainThread])
{
    [self performSelectorOnMainThread:@selector(start) withObject:nil waitUntilDone:NO];
    return;
}

in Ihrer start Methode.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top