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")
}


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow