¿Llamar a un método en el hilo principal?


82

En primer lugar, estoy escribiendo código para iphone. Necesito poder llamar a un método en el hilo principal sin usar performSelectorOnMainThread. La razón por la que no quiero usar performSelectorOnMainThreades que causa problemas cuando intento crear una simulación para pruebas unitarias.

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

El problema es que mi simulacro sabe cómo llamar doSomethingpero no sabe cómo llamar performSelectorOnMainThread.

Entonces, ¿alguna solución?

Respuestas:


272

C objetivo

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

Rápido

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

Legacy Swift

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

Acabas de alegrarme el día con el código Swift 3. ¡Gracias!
Felipe Balduino

Es una buena práctica no usar uno mismo directamente en el bloque. en su lugar, use una referencia débil.
Jageen

2

Hay un dicho en el software que dice que agregar una capa de indirección arreglará casi cualquier cosa.

Haga que el método doSomething sea un shell de indirección que solo hace un performSelectorOnMainThread para llamar al método really_doSomething para hacer el trabajo real de Something. O, si no desea cambiar su método doSomething, haga que la unidad de prueba simulada llame a un método doSomething_redirect_shell para hacer algo similar.


1

Aquí hay una mejor manera de hacer esto en Swift:

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

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

Está incluido como una función estándar en mi repositorio, compruébalo: https://github.com/goktugyil/EZSwiftExtensions


Esto no es mejor de ninguna manera, creaste una función que no hace nada más que llamar a otra. por cierto, la sintaxis rápida se puede simplificar aún más "() -> Void in" no es necesario
aryaxt

Es más legible / escribible por humanos. Sí, autocompletar agrega en "() -> Void in". ¿Hay alguna forma de deshabilitar este comportamiento de autocompletar en void> void closures?
Esqarrouth

el nombre del método que tiene podría ser engañoso, parece que el bloque se ejecutaría de inmediato en el hilo principal, pero eso no es cierto. dispatch_async en la cola principal agrega el bloque de código al siguiente runloop, este comportamiento importante está oculto detrás del método llamado "runThisInMainThread
aryaxt

1
este es el comportamiento esperado, dispatch_async agrega el código al final de la cola. Si desea que lo llamen de inmediato, debe usar dispatch_sync en su lugar. Si envía dispatch_sync en una cola para el hilo en el que ya está, se produce un bloqueo del hilo. en su ejemplo, el orden de las impresiones es "a", "c", "b". ayc se ejecutan en 1 runloop porque están en el mismo ámbito. b se agrega al final de la cola, por lo que a veces se llama más tarde cuando se completan los otros elementos existentes en la cola
aryaxt

1
@Esqarrouth: ¿está SEGURO de su dispatch_asynccódigo bloqueado después de llamarlo? El objetivo de usar en asynclugar de syncNO es bloquear lo que sigue. (Por supuesto, el blockcódigo bloqueará cualquier otra cosa en el hilo principal , ya que el objetivo del código solicitado es ejecutarse en el hilo principal. Si desea ejecutar código en segundo plano, entonces debe solicitar una cola diferente, no dispatch_get_main_queue.)
ToolmakerSteve

1

Y ahora en 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
        }

    }
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.