Eine Methode im Hauptthread aufrufen?

82

Zunächst schreibe ich Code für das iPhone. Ich muss in der Lage sein, eine Methode im Hauptthread aufzurufen, ohne sie zu verwenden performSelectorOnMainThread. Der Grund, den ich nicht verwenden möchte, performSelectorOnMainThreadist, dass es Probleme verursacht, wenn ich versuche, ein Modell für Unit-Tests zu erstellen.

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

Das Problem ist, dass mein Mock weiß, wie man anruft, doSomethingaber er weiß nicht, wie man anruft performSelectorOnMainThread.

Also irgendeine Lösung?

aryaxt
quelle

Antworten:

271

Ziel c

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

Schnell

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

Legacy Swift

dispatch_async(dispatch_get_main_queue()) {
    self.doSomething()
}
aryaxt
quelle
Du hast gerade meinen Tag mit dem schnellen 3-Code gemacht. Vielen Dank!
Felipe Balduino
Es ist eine gute Praxis, sich nicht direkt in Block zu verwenden. Verwenden Sie stattdessen eine schwache Referenz.
Jageen
2

In der Software gibt es ein Sprichwort, dass das Hinzufügen einer Indirektionsebene fast alles behebt.

Die doSomething-Methode muss eine Indirektionsshell sein, die nur einen performSelectorOnMainThread ausführt, um die Really_doSomething-Methode aufzurufen und die eigentliche Something-Arbeit auszuführen. Wenn Sie Ihre doSomething-Methode nicht ändern möchten, lassen Sie die Mock-Testeinheit eine doSomething_redirect_shell-Methode aufrufen, um etwas Ähnliches zu tun.

hotpaw2
quelle
1

Hier ist ein besserer Weg, dies in Swift zu tun:

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

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

Es ist als Standardfunktion in meinem Repo enthalten. Schauen Sie sich das an: https://github.com/goktugyil/EZSwiftExtensions

Esqarrouth
quelle
Dies ist in keiner Weise besser. Sie haben eine Funktion erstellt, die nichts anderes tut, als eine andere aufzurufen.
Übrigens
Es ist menschlicher lesbar / beschreibbar. Ja, Autocomplete fügt "() -> Void in" hinzu. Gibt es überhaupt eine Möglichkeit, dieses Autovervollständigungsverhalten bei void> void-Schließungen zu deaktivieren?
Esqarrouth
Der Methodenname, den Sie haben, könnte irreführend sein. Es hört sich so an, als würde der Block sofort im Hauptthread ausgeführt, aber das stimmt nicht. dispatch_async in der Hauptwarteschlange fügt den Codeblock zum nächsten Runloop hinzu. Dieses wichtige Verhalten verbirgt sich hinter der Methode "runThisInMainThread
aryaxt
1
Dies ist das erwartete Verhalten. dispatch_async fügt den Code am Ende der Warteschlange hinzu. Wenn Sie möchten, dass es sofort aufgerufen wird, sollten Sie stattdessen dispatch_sync ausführen. Wenn Sie dispatch_sync in einer Warteschlange für den Thread ausführen, in dem Sie sich bereits befinden, wird eine Thread-Sperre ausgelöst. In Ihrem Beispiel lautet die Reihenfolge der Ausdrucke "a", "c", "b". a und c werden in einem Runloop ausgeführt, da sie sich im selben Bereich befinden. b wird am Ende der Warteschlange hinzugefügt, so dass es manchmal später aufgerufen wird, wenn die anderen vorhandenen Elemente in der Warteschlange abgeschlossen sind
aryaxt
1
@Esqarrouth - Sind Sie sicher, dass Ihr dispatch_asyncCode nach dem Aufruf gesperrt ist? Der ganze Sinn der Verwendung asyncstatt synczu blockieren besteht darin, das Folgende NICHT zu blockieren. (Natürlich blockblockiert der of-Code alles andere im Hauptthread , da der angeforderte Code im Hauptthread ausgeführt werden soll. Wenn Sie Hintergrundcode ausführen möchten, fragen Sie nach einer anderen Warteschlange. nicht dispatch_get_main_queue.)
ToolmakerSteve
1

Und jetzt in Swift 3:

DispatchQueue.main.async{
   self.doSomething()
}
RomOne
quelle
-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
        }

    }
Muhammad Zeeshan
quelle