Szukaj…
Wprowadzenie
Temat pokrewny: Grand Central Dispatch
Składnia
- dispatch_async - uruchamia blok kodu w osobnej kolejce i nie zatrzymuje bieżącej kolejki. Jeśli kolejka znajduje się w innym wątku niż ten, w którym została wywołana metoda dispatch_async, kod w bloku będzie działał, podczas gdy kod również po uruchomieniu dispatch_async
- dispatch_sync - uruchamia blok kodu w oddzielnym kolejki i kończy bieżącą kolejką. Jeśli kolejka znajduje się w innym wątku niż ten, w którym została wywołana metoda dispatch_async, kod w bloku zostanie uruchomiony, a wykonanie w wątku, w którym wywołano metodę, zostanie wznowione dopiero po jej zakończeniu
Parametry
kolejka | Kolejka, w której będzie działał kod w bloku wysyłki. Kolejka jest jak (ale nie dokładnie taka sama jak) wątek; kod w różnych kolejkach może działać równolegle. Użyj dispatch_get_main_queue aby uzyskać kolejkę dla głównego wątku Aby utworzyć nową kolejkę, która z kolei tworzy nowy wątek, użyj dispatch_queue_create("QUEUE_NAME", DISPATCH_QUEUE_CONCURRENT) . Pierwszym parametrem jest nazwa kolejki, która jest wyświetlana w debuggerze, jeśli zatrzymasz się, gdy blok jest nadal uruchomiony. Drugi parametr nie ma znaczenia, chyba że chcesz użyć tej samej kolejki do wielu wywołań dispatch_async lub dispatch_sync . Opisuje, co się stanie, gdy kolejny blok zostanie umieszczony w tej samej kolejce; DISPATCH_QUEUE_CONCURRENT spowoduje, że oba bloki będą działały jednocześnie, natomiast DISPATCH_QUEUE_SERIAL sprawi, że drugi blok będzie czekać na zakończenie pierwszego bloku |
---|---|
blok | Kod w tym bloku będzie działał w queue ; umieść tutaj kod, który chcesz uruchomić w osobnej kolejce. Pomocna wskazówka: jeśli piszesz to w Xcode, a argument bloku ma niebieski kontur wokół niego, kliknij dwukrotnie argument, a Xcode automatycznie utworzy pusty blok (dotyczy to wszystkich argumentów bloku w dowolnej funkcji lub metodzie) |
Uwagi
Ilekroć robisz coś w osobnym wątku, co dzieje się podczas korzystania z kolejek, ważne jest, aby zachować bezpieczeństwo wątku. Niektóre metody, w szczególności dla UIView
, mogą nie działać i / lub zawieszać się na wątkach innych niż wątek główny. Pamiętaj też, aby nie zmieniać niczego (zmiennych, właściwości itp.), Które są również używane w głównym wątku, chyba że rozliczasz się z tą zmianą
Uruchamianie kodu jednocześnie - Uruchamianie kodu podczas uruchamiania innego kodu
Powiedz, że chcesz wykonać akcję (w tym przypadku logowanie „Foo”), jednocześnie robiąc coś innego (logowanie „Bar”). Zwykle, jeśli nie używasz współbieżności, jedna z tych akcji zostanie w pełni wykonana, a druga zostanie uruchomiona dopiero po jej całkowitym zakończeniu. Ale dzięki współbieżności możesz wykonać obie akcje jednocześnie:
dispatch_async(dispatch_queue_create("Foo", DISPATCH_QUEUE_CONCURRENT), ^{
for (int i = 0; i < 100; i++) {
NSLog(@"Foo");
usleep(100000);
}
});
for (int i = 0; i < 100; i++) {
NSLog(@"Bar");
usleep(50000);
}
Spowoduje to zalogowanie „Foo” 100 razy, zatrzymanie na 100 ms przy każdym logowaniu, ale zrobi to wszystko w osobnym wątku. Podczas rejestrowania Foo
, „Bar” będzie także logowany w odstępach co 50 ms, jednocześnie. Idealnie powinieneś zobaczyć wyjście z „Foo” i „Bars” zmieszanymi razem
Wykonanie w głównym wątku
Podczas wykonywania zadań asynchronicznie zazwyczaj pojawia się potrzeba upewnienia się, że fragment kodu jest uruchamiany w głównym wątku. Na przykład możesz chcieć trafić API REST asynchronicznie, ale umieść wynik w UILabel na ekranie. Przed aktualizacją UILabel musisz upewnić się, że Twój kod jest uruchomiony w głównym wątku:
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
//Perform expensive tasks
//...
//Now before updating the UI, ensure we are back on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
label.text = //....
});
}
Za każdym razem, gdy aktualizujesz widoki na ekranie, zawsze upewnij się, że robisz to w głównym wątku, w przeciwnym razie może wystąpić niezdefiniowane zachowanie.
Grupa wysyłkowa - oczekiwanie na zakończenie innych wątków.
dispatch_group_t preapreWaitingGroup = dispatch_group_create();
dispatch_group_enter(preapreWaitingGroup);
[self doAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
// Notify that this task has been completed.
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_enter(preapreWaitingGroup);
[self doOtherAsynchronousTaskWithComplete:^(id someResults, NSError *error) {
dispatch_group_leave(preapreWaitingGroup);
}]
dispatch_group_notify(preapreWaitingGroup, dispatch_get_main_queue(), ^{
// This block will be executed once all above threads completed and call dispatch_group_leave
NSLog(@"Prepare completed. I'm readyyyy");
});
Aktualizacja 1. Wersja Swift 3.
let prepareGroup = DispatchGroup()
prepareGroup.enter()
doAsynchronousTaskWithComplete() { (someResults, error) in
// Notify that this task has been completed.
prepareGroup.leave()
}
prepareGroup.enter()
doOtherAsynchronousTaskWithComplete() { (someResults, error) in
// Notify that this task has been completed.
prepareGroup.leave()
}
prepareGroup.notify(queue: DispatchQueue.main) {
// This block will be executed once all above threads completed and call dispatch_group_leave
print("Prepare completed. I'm readyyyy")
}