NSOperationQueue
hat waitUntilAllOperationsAreFinished
, aber ich möchte nicht synchron darauf warten. Ich möchte nur die Fortschrittsanzeige in der Benutzeroberfläche ausblenden, wenn die Warteschlange beendet ist.
Was ist der beste Weg, um dies zu erreichen?
Ich kann keine Benachrichtigungen von meinem NSOperation
s senden , da ich nicht weiß, welche die letzte sein wird, und [queue operations]
möglicherweise noch nicht leer (oder schlimmer noch - neu gefüllt) ist, wenn eine Benachrichtigung eingeht.
Antworten:
Verwenden Sie KVO, um die
operations
Eigenschaft Ihrer Warteschlange zu beobachten. Anschließend können Sie feststellen, ob Ihre Warteschlange vollständig ist, indem Sie nach prüfen[queue.operations count] == 0
.Deklarieren Sie irgendwo in der Datei, in der Sie die KVO ausführen, einen Kontext für KVO wie folgt ( weitere Informationen ):
Gehen Sie beim Einrichten Ihrer Warteschlange folgendermaßen vor:
Dann machen Sie dies in Ihrem
observeValueForKeyPath
:(Dies setzt voraus, dass Sie
NSOperationQueue
sich in einer Eigenschaft mit dem Namen befinden.queue
)Irgendwann, bevor Ihr Objekt vollständig freigegeben wird (oder wenn es sich nicht mehr um den Warteschlangenstatus kümmert), müssen Sie die Registrierung von KVO wie folgt aufheben:
Nachtrag: iOS 4.0 hat eine
NSOperationQueue.operationCount
Eigenschaft, die laut Dokumentation KVO-konform ist. Diese Antwort funktioniert jedoch weiterhin in iOS 4.0, sodass sie für die Abwärtskompatibilität weiterhin nützlich ist.quelle
operationCount
dasselbeNSOperationQueue
Objekt zu beobachten, würde möglicherweise zu Fehlern führen. In diesem Fall müssten Sie das Kontextargument ordnungsgemäß verwenden. Es ist unwahrscheinlich, aber definitiv möglich. (Das eigentliche Problem zu formulieren ist hilfreicher als das Hinzufügen von Snark + einem Link)Wenn Sie etwas erwarten (oder wünschen), das diesem Verhalten entspricht:
Sie sollten sich bewusst sein, dass beim Hinzufügen mehrerer "kurzer" Vorgänge zu einer Warteschlange möglicherweise stattdessen dieses Verhalten angezeigt wird (da Vorgänge als Teil des Hinzufügens zur Warteschlange gestartet werden):
In meinem Projekt musste ich wissen, wann der letzte Vorgang abgeschlossen war, nachdem eine große Anzahl von Vorgängen zu einer seriellen NSOperationQueue hinzugefügt wurde (dh maxConcurrentOperationCount = 1) und erst, wenn alle abgeschlossen waren.
Googeln Ich habe diese Aussage eines Apple-Entwicklers als Antwort auf die Frage "Ist ein serielles NSoperationQueue-FIFO?" Gefunden. - -
In meinem Fall ist es möglich zu wissen, wann der letzte Vorgang zur Warteschlange hinzugefügt wurde. Nachdem der letzte Vorgang hinzugefügt wurde, füge ich der Warteschlange einen weiteren Vorgang mit niedrigerer Priorität hinzu, der lediglich die Benachrichtigung sendet, dass die Warteschlange geleert wurde. Aufgrund der Aussage von Apple wird so sichergestellt, dass nur eine einzige Benachrichtigung gesendet wird, nachdem alle Vorgänge abgeschlossen wurden.
Wenn Operationen auf eine Weise hinzugefügt werden, die es nicht erlaubt, die letzte zu erkennen (dh nicht deterministisch), dann müssen Sie meiner Meinung nach mit den oben genannten KVO-Ansätzen fortfahren und zusätzliche Schutzlogik hinzufügen, um zu versuchen, weitere zu erkennen Operationen können hinzugefügt werden.
:) :)
quelle
Wie wäre es mit dem Hinzufügen einer NSOperation, die von allen anderen abhängig ist, damit sie zuletzt ausgeführt wird?
quelle
Eine Alternative ist die Verwendung von GCD. Siehe diese als Referenz.
quelle
So mache ich es.
Richten Sie die Warteschlange ein und registrieren Sie sich für Änderungen in der Operationseigenschaft:
... und der Beobachter (in diesem Fall
self
) implementiert:In diesem Beispiel zeigt "Spinner"
UIActivityIndicatorView
, dass etwas passiert. Natürlich können Sie nach Bedarf wechseln ...quelle
for
Schleife scheint potenziell teuer zu sein (was ist, wenn Sie alle Vorgänge auf einmal abbrechen? Würde das nicht eine quadratische Leistung bringen, wenn die Warteschlange bereinigt wird?)Ich benutze dazu eine Kategorie.
NSOperationQueue + Completion.h
NSOperationQueue + Completion.m
Verwendung :
Quelle: https://gist.github.com/artemstepanenko/7620471
quelle
waitUntilFinished
sollte seinYES
Ab iOS 13.0 sind die Eigenschaften operationCount und operation veraltet. Es ist genauso einfach, die Anzahl der Vorgänge in Ihrer Warteschlange selbst zu verfolgen und eine Benachrichtigung auszulösen, wenn alle abgeschlossen sind. Dieses Beispiel funktioniert auch mit einer asynchronen Unterklasse von Operation .
Unten finden Sie eine Unterklasse von Operation für einfache asynchrone Operationen
}}
quelle
decrementOperationCount()
Methode aufgerufen?Was ist mit KVO, um die
operationCount
Eigenschaft der Warteschlange zu beobachten ? Dann würden Sie davon hören, wenn die Warteschlange leer wurde und auch wenn sie nicht mehr leer war. Der Umgang mit der Fortschrittsanzeige kann so einfach sein wie:quelle
NSOperationQueue
beschwert sich der ab 3.1, dass er für den Schlüssel nicht KVO-konform istoperationCount
.operationCount
Eigenschaft vorhanden.Fügen Sie die letzte Operation wie folgt hinzu:
So:
quelle
Mit ReactiveObjC finde ich, dass dies gut funktioniert:
quelle
Zu Ihrer Information, Sie können dies mit GCD dispatch_group in Swift 3 erreichen . Sie können benachrichtigt werden, wenn alle Aufgaben abgeschlossen sind.
quelle
Sie können eine neue erstellen
NSThread
oder eine Auswahl im Hintergrund ausführen und dort warten. Wenn derNSOperationQueue
Vorgang abgeschlossen ist, können Sie eine eigene Benachrichtigung senden.Ich denke an etwas wie:
quelle
Wenn Sie diese Operation als Basisklasse verwenden, können Sie den
whenEmpty {}
Block an die OperationQueue übergeben :quelle
Ohne KVO
quelle
Wenn Sie hier nach einer Lösung mit Mähdrescher gesucht haben, habe ich mir nur mein eigenes Statusobjekt angehört.
quelle