Wywołanie metody w głównym wątku?


83

Przede wszystkim piszę kod na iPhone'a. Muszę mieć możliwość wywołania metody w głównym wątku bez użycia performSelectorOnMainThread. Powodem, którego nie chcę używać, performSelectorOnMainThreadjest to, że powoduje to problem, gdy próbuję utworzyć makietę do testów jednostkowych.

[self performSelectorOnMainThread:@Selector(doSomething) withObject:nil];

Problem polega na tym, że mój makieta wie, jak dzwonić, doSomethingale nie wie, jak dzwonić performSelectorOnMainThread.

Więc jakieś rozwiązanie?

Odpowiedzi:


274

Cel C

dispatch_async(dispatch_get_main_queue(), ^{
    [self doSomething];
});

Szybki

DispatchQueue.main.async {
    self.doSomething()
}

Legacy Swift

dispatch_async(dispatch_get_main_queue()) {
    self.doSomething()
}

Udało Ci się właśnie zrobić mój dzień dzięki szybkiemu kodowi 3. Dzięki!
— Felipe Balduino

Dobrą praktyką jest nie używać siebie bezpośrednio do bloku. zamiast tego użyj słabego odniesienia do niego.
— Jageen

2

W oprogramowaniu jest takie powiedzenie, że dodanie warstwy pośredniej naprawi prawie wszystko.

Niech metoda doSomething będzie powłoką pośrednią, która wykonuje tylko performSelectorOnMainThread w celu wywołania metody really_doSomething w celu wykonania rzeczywistej pracy Something. Lub, jeśli nie chcesz zmieniać metody doSomething, poproś jednostkę testową o wywołanie metody doSomething_redirect_shell, aby zrobić coś podobnego.


1

Oto lepszy sposób na zrobienie tego w Swift:

runThisInMainThread { () -> Void in
    // Run your code
    self.doSomething()
}

func runThisInMainThread(block: dispatch_block_t) {
    dispatch_async(dispatch_get_main_queue(), block)
}

Jest zawarta jako standardowa funkcja w moim repozytorium, sprawdź: https://github.com/goktugyil/EZSwiftExtensions


Nie jest to w żaden sposób lepsze, stworzyłeś funkcję, która nic nie robi, tylko wywołuje inną. tak przy okazji, że szybką składnię można jeszcze bardziej uprościć "() -> Void in" nie jest potrzebne
— aryaxt

Jest bardziej czytelny / zapisywalny dla człowieka. Tak, autouzupełnianie dodaje „() -> Void in”. Czy w ogóle można wyłączyć to zachowanie autouzupełniania w void> void closures?
— Esqarrouth

nazwa metody, którą masz, może być myląca, wygląda na to, że blok zostałby wykonany od razu w głównym wątku, ale to nieprawda. dispatch_async w głównej kolejce dodaje blok kodu do następnego runloop, to ważne zachowanie jest ukryte za metodą o nazwie „runThisInMainThread
— aryaxt

1
jest to oczekiwane zachowanie, dispatch_async dodaje kod na końcu kolejki. Jeśli chcesz, aby został wywołany od razu, powinieneś zamiast tego zrobić dispatch_sync. Jeśli wykonasz dispatch_sync w kolejce dla wątku, w którym już jesteś, spowoduje to blokadę wątku. w twoim przykładzie kolejność wydruków to „a”, „c”, „b”. a i c są wykonywane w 1 runloop, ponieważ są w tym samym zakresie. b jest dodawany na koniec kolejki, więc czasami jest wywoływany później, gdy inne istniejące pozycje w kolejce zostaną ukończone
— aryaxt

1
@Esqarrouth - czy NA PEWNO masz dispatch_asynczablokowany kod po wywołaniu go? Cały sens używania asynczamiast syncNIE blokować tego, co następuje. (Oczywiście blockkod BĘDZIE zablokował wszystko inne w głównym wątku , ponieważ celem żądanego kodu jest wykonanie w głównym wątku. Jeśli chcesz uruchomić kod w tle, poprosiłbyś o inną kolejkę, nie dispatch_get_main_queue)
— ToolmakerSteve

1

A teraz w Swift 3:

DispatchQueue.main.async{
   self.doSomething()
}

-4
// Draw Line
    func drawPath(from polyStr: String){
        DispatchQueue.main.async {
            let path = GMSPath(fromEncodedPath: polyStr)
            let polyline = GMSPolyline(path: path)
            polyline.strokeWidth = 3.0
            polyline.strokeColor = #colorLiteral(red: 0.05098039216, green: 0.5764705882, blue: 0.2784313725, alpha: 1)
            polyline.map = self.mapVu // Google MapView
        }

    }
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.