Ich habe eine Methode, die einen Block und einen Abschlussblock akzeptiert. Der erste Block sollte im Hintergrund ausgeführt werden, während der Abschlussblock in der Warteschlange ausgeführt werden sollte, in der die Methode aufgerufen wurde.
Für letztere habe ich immer verwendet dispatch_get_current_queue()
, aber es scheint, dass es in iOS 6 oder höher veraltet ist. Was soll ich stattdessen verwenden?
dispatch_get_current_queue()
ist das in iOS 6 veraltet? Die Dokumente sagen nichts darüberAntworten:
Das Muster "In der Warteschlange ausführen, in der sich der Anrufer befand" ist ansprechend, aber letztendlich keine gute Idee. Diese Warteschlange kann eine Warteschlange mit niedriger Priorität, die Hauptwarteschlange oder eine andere Warteschlange mit ungeraden Eigenschaften sein.
Mein bevorzugter Ansatz hierfür ist zu sagen, dass "der Abschlussblock in einer implementierungsdefinierten Warteschlange mit den folgenden Eigenschaften ausgeführt wird: x, y, z" und den Block an eine bestimmte Warteschlange senden zu lassen, wenn der Aufrufer mehr Kontrolle als diese wünscht. Ein typischer Satz von Eigenschaften, die angegeben werden müssen, ist "seriell, nicht wiedereintrittsfähig und asynchron in Bezug auf jede andere für Anwendungen sichtbare Warteschlange".
** BEARBEITEN **
Catfish_Man hat in den Kommentaren unten ein Beispiel angegeben. Ich füge es nur seiner Antwort hinzu.
quelle
Dies ist grundsätzlich der falsche Ansatz für die von Ihnen beschriebene API. Wenn eine API einen Block und einen Abschlussblock zum Ausführen akzeptiert, müssen die folgenden Fakten zutreffen:
Der "auszuführende Block" sollte in einer internen Warteschlange ausgeführt werden, z. B. einer Warteschlange, die für die API privat ist und daher vollständig unter der Kontrolle dieser API steht. Die einzige Ausnahme besteht darin, dass die API ausdrücklich deklariert, dass der Block in der Hauptwarteschlange oder einer der globalen gleichzeitigen Warteschlangen ausgeführt wird.
Der Abschlussblock sollte immer als Tupel (Warteschlange, Block) ausgedrückt werden, es sei denn, die gleichen Annahmen wie für Nr. 1 gelten, z. B. wird der Abschlussblock in einer bekannten globalen Warteschlange ausgeführt. Der Abschlussblock sollte außerdem asynchron in der übergebenen Warteschlange gesendet werden.
Dies sind nicht nur Stilpunkte, sondern unbedingt erforderlich, wenn Ihre API vor Deadlocks oder anderen Randfällen geschützt werden soll, die Sie sonst eines Tages am nächsten Baum hängen lassen. :-)
quelle
Die anderen Antworten sind großartig, aber für mich ist die Antwort strukturell. Ich habe eine Methode wie diese auf einem Singleton:
Das hat zwei Abhängigkeiten, die sind:
und
Auf diese Weise zentralisiere ich meine Anrufe, um sie auf dem anderen Thread zu versenden.
quelle
Sie sollten
dispatch_get_current_queue
in erster Linie vorsichtig mit Ihrer Verwendung sein . Aus der Header-Datei:Sie können eines von zwei Dingen tun:
Behalten Sie einen Verweis auf die Warteschlange bei, in der Sie ursprünglich gepostet haben (sofern Sie ihn über erstellt haben
dispatch_queue_create
), und verwenden Sie diesen fortan.Verwenden Sie systemdefinierte Warteschlangen über
dispatch_get_global_queue
und verfolgen Sie, welche Sie verwenden.Während Sie sich zuvor auf das System verlassen haben, um die Warteschlange zu verfolgen, in der Sie sich befinden, müssen Sie dies effektiv selbst tun.
quelle
dispatch_get_current_queue()
herausfinden können, um welche Warteschlange es sich handelt? Manchmal hat der Code, der wissen muss, in welcher Warteschlange er ausgeführt wird, keine Kontrolle oder Kenntnis davon. Ich habe viel Code, der in einer Hintergrundwarteschlange ausgeführt werden kann (und sollte), muss aber gelegentlich die GUI (Fortschrittsbalken usw.) aktualisieren und muss daher dispatch_sync () für diese Vorgänge in die Hauptwarteschlange übertragen. Wenn sich dispatch_sync () bereits in der Hauptwarteschlange befindet, wird es für immer gesperrt. Ich werde Monate brauchen, um meinen Code dafür umzugestalten.Apple war veraltet
dispatch_get_current_queue()
, hat aber an anderer Stelle ein Loch hinterlassen, sodass wir immer noch die aktuelle Versandwarteschlange abrufen können:Dies funktioniert zumindest für die Hauptwarteschlange. Beachten Sie, dass diese
underlyingQueue
Eigenschaft seit iOS 8 verfügbar ist.Wenn Sie den Abschlussblock in der ursprünglichen Warteschlange ausführen müssen, können Sie ihn auch
OperationQueue
direkt verwenden, ich meine ohne GCD.quelle
Für diejenigen, die noch einen Warteschlangenvergleich benötigen, können Sie Warteschlangen anhand ihrer Bezeichnung oder Angabe vergleichen. Überprüfen Sie dies unter https://stackoverflow.com/a/23220741/1531141
quelle
Dies ist auch eine Antwort von mir. Also werde ich über unseren Anwendungsfall sprechen.
Wir haben eine Serviceschicht und die UI-Schicht (unter anderem). Die Serviceschicht führt Aufgaben im Hintergrund aus. (Datenmanipulationsaufgaben, CoreData-Aufgaben, Netzwerkaufrufe usw.). Die Serviceschicht verfügt über einige Operationswarteschlangen, um die Anforderungen der UI-Schicht zu erfüllen.
Die UI-Schicht verlässt sich auf die Services-Schicht, um ihre Arbeit zu erledigen und dann einen Erfolgsabschlussblock auszuführen. Dieser Block kann UIKit-Code enthalten. Ein einfacher Anwendungsfall besteht darin, alle Nachrichten vom Server abzurufen und die Sammlungsansicht neu zu laden.
Hier garantieren wir, dass die Blöcke, die an die Serviceschicht übergeben werden, in der Warteschlange versendet werden, in der der Service aufgerufen wurde. Da dispatch_get_current_queue eine veraltete Methode ist, verwenden wir NSOperationQueue.currentQueue, um die aktuelle Warteschlange des Anrufers abzurufen. Wichtiger Hinweis zu dieser Eigenschaft.
Da wir unsere Dienste immer in einer bekannten Warteschlange (unseren benutzerdefinierten Warteschlangen und der Hauptwarteschlange) aufrufen, funktioniert dies gut für uns. Wir haben Fälle, in denen serviceA serviceB aufrufen kann, die serviceC aufrufen können. Da wir steuern, woher der erste Serviceabruf stammt, wissen wir, dass der Rest der Services denselben Regeln folgt.
Daher gibt NSOperationQueue.currentQueue immer eine unserer Warteschlangen oder die MainQueue zurück.
quelle