Mam metodę, która akceptuje blok i blok uzupełniania. Pierwszy blok powinien działać w tle, a blok uzupełniania w dowolnej kolejce, w której wywołano metodę.
W przypadku tego ostatniego zawsze używałem dispatch_get_current_queue()
, ale wygląda na to, że jest przestarzały w iOS 6 lub nowszym. Czego powinienem użyć zamiast tego?
dispatch_get_current_queue()
jest przestarzały w iOS 6?Odpowiedzi:
Wzorzec „uruchamiaj w dowolnej kolejce, w której był dzwoniący” jest atrakcyjny, ale ostatecznie nie jest to świetny pomysł. Ta kolejka może być kolejką o niskim priorytecie, kolejką główną lub inną kolejką o nieparzystych właściwościach.
Moim ulubionym podejściem jest stwierdzenie, że „blok uzupełniania działa na kolejce zdefiniowanej w ramach implementacji z następującymi właściwościami: x, y, z” i pozwolenie blokowi na wysłanie do określonej kolejki, jeśli wywołujący chce mieć większą kontrolę. Typowy zestaw właściwości do określenia to coś w rodzaju „szeregowy, niewprowadzający ponownie i asynchroniczny w odniesieniu do każdej innej kolejki widocznej dla aplikacji”.
** EDYTOWAĆ **
Catfish_Man umieścił przykład w komentarzach poniżej, po prostu dodaję go do jego odpowiedzi.
źródło
Jest to zasadniczo niewłaściwe podejście do opisywanego interfejsu API. Jeśli interfejs API akceptuje blok i blok uzupełniania do uruchomienia, muszą być spełnione następujące fakty:
„Blok do uruchomienia” powinien być uruchamiany w kolejce wewnętrznej, np. Kolejce prywatnej dla API, a zatem całkowicie pod kontrolą tego API. Jedynym wyjątkiem jest sytuacja, gdy interfejs API wyraźnie deklaruje, że blok zostanie uruchomiony w głównej kolejce lub w jednej z globalnych kolejek współbieżnych.
Blok uzupełniania powinien zawsze być wyrażony jako krotka (kolejka, blok), chyba że te same założenia, co dla # 1 są prawdziwe, np. Blok uzupełniania zostanie uruchomiony na znanej globalnej kolejce. Blok uzupełniania powinien ponadto być wysyłany asynchronicznie w kolejce przekazanej.
To nie są tylko punkty stylistyczne, są one całkowicie konieczne, jeśli twoje API ma być bezpieczne przed zakleszczeniami lub innymi zachowaniami skrajnymi, które w przeciwnym razie spowodują zawieszenie cię kiedyś na najbliższym drzewie. :-)
źródło
Inne odpowiedzi są świetne, ale dla mnie odpowiedź jest strukturalna. Mam taką metodę, która jest na Singletonie:
który ma dwie zależności, którymi są:
i
W ten sposób scentralizuję wywołania, które mają być wysyłane w drugim wątku.
źródło
Przede wszystkim należy zachować ostrożność podczas korzystania z
dispatch_get_current_queue
. Z pliku nagłówkowego:Możesz zrobić jedną z dwóch rzeczy:
Zachowaj odniesienie do kolejki, w której pierwotnie opublikowałeś (jeśli utworzyłeś ją przez
dispatch_queue_create
) i używaj tego od tej pory.Korzystaj z kolejek zdefiniowanych przez system za pośrednictwem
dispatch_get_global_queue
i śledź, z której korzystasz.Skutecznie, choć wcześniej polegałeś na systemie, który śledzi kolejkę, w której się znajdujesz, będziesz musiał to zrobić samodzielnie.
źródło
dispatch_get_current_queue()
do sprawdzenia, która to kolejka? Czasami kod, który musi wiedzieć, w której kolejce działa, nie ma o nim żadnej kontroli ani wiedzy. Mam dużo kodu, który może (i powinien) być wykonywany w kolejce w tle, ale czasami trzeba zaktualizować GUI (pasek postępu itp.), I dlatego potrzebuję dispatch_sync () do głównej kolejki dla tych operacji. Jeśli już znajduje się w głównej kolejce, dispatch_sync () zablokuje się na zawsze. Refaktoryzacja kodu zajmie mi miesiące.Firma Apple wycofała się
dispatch_get_current_queue()
, ale pozostawiła lukę w innym miejscu, więc nadal możemy uzyskać bieżącą kolejkę wysyłek:Działa to przynajmniej dla głównej kolejki. Pamiętaj, że ta
underlyingQueue
właściwość jest dostępna od iOS 8.Jeśli potrzebujesz wykonać blok uzupełniania w oryginalnej kolejce, możesz również użyć
OperationQueue
bezpośrednio, tj. Bez GCD.źródło
Ci, którzy nadal potrzebują porównywania w kolejce, mogą porównać kolejki według ich etykiety lub specyfikacji. Sprawdź to https://stackoverflow.com/a/23220741/1531141
źródło
To jest odpowiedź dla mnie też. Więc opowiem o naszym przypadku użycia.
Mamy warstwę usług i warstwę interfejsu użytkownika (między innymi). Warstwa usług uruchamia zadania w tle. (Zadania manipulacji danymi, zadania CoreData, połączenia sieciowe itp.). Warstwa usług ma kilka kolejek operacji, aby zaspokoić potrzeby warstwy interfejsu użytkownika.
Warstwa UI polega na warstwie usług, aby wykonać swoją pracę, a następnie uruchomić blok ukończenia sukcesu. Ten blok może zawierać kod UIKit. Prostym przypadkiem użycia jest pobranie wszystkich wiadomości z serwera i ponowne załadowanie widoku kolekcji.
Tutaj gwarantujemy, że bloki przekazywane do warstwy usług są wysyłane w kolejce, w której usługa została wywołana. Ponieważ dispatch_get_current_queue jest przestarzałą metodą, używamy NSOperationQueue.currentQueue, aby uzyskać bieżącą kolejkę wywołującego. Ważna uwaga na temat tej nieruchomości.
Ponieważ zawsze wywołujemy nasze usługi w znanej kolejce (nasze kolejki niestandardowe i kolejka główna), działa to dobrze dla nas. Mamy przypadki, w których serviceA może wezwać serviceB, który może wezwać serviceC. Ponieważ kontrolujemy, skąd jest wykonywane pierwsze zgłoszenie serwisowe, wiemy, że pozostałe usługi będą podlegać tym samym regułom.
Zatem NSOperationQueue.currentQueue zawsze zwróci jedną z naszych kolejek lub MainQueue.
źródło