En Swift ¿cómo llamar al método con parámetros en el hilo principal de GCD?


En mi aplicación tengo una función que hace una NSRURLSession y envía una NSURLRequest usando

sesh.dataTaskWithRequest(req, completionHandler: {(data, response, error)

En el bloque completion para esta tarea, necesito hacer algún cálculo que agregue una UIImage al controlador viewcontroller que llama. Tengo un func llamado

func displayQRCode(receiveAddr, withAmountInBTC:amountBTC)

Que hace el cálculo de adición de UIImage. Si intento ejecutar el código de adición de vista dentro del bloque de finalización, Xcode arroja un error diciendo que no puedo usar el motor de diseño mientras estoy en un proceso en segundo plano. Así que encontré algún código encendido para que intente poner en cola un método en el hilo principal:

let time = dispatch_time(DISPATCH_TIME_NOW, Int64(0.0 * Double(NSEC_PER_MSEC)))
                    dispatch_after(time, dispatch_get_main_queue(), {
                        let returned = UIApplication.sharedApplication().sendAction("displayQRCode:", to: self.delegate, from: self, forEvent: nil)
                        })

Sin embargo, no se como agregar los parámetros "receiveAddr" y "amountBTC" a esta llamada a la función. ¿Cómo haría esto, o puede alguien sugerir una forma óptima para agregar una llamada a un método a la cola principal de la aplicación?

Author: almel, 2014-07-28

8 answers

Simplemente escribe esto en completion handler. No es necesario usar dispatch_after

dispatch_async(dispatch_get_main_queue(), {
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
})

Swift 3:

DispatchQueue.main.async { 
  let delegateObj = UIApplication.sharedApplication().delegate as YourAppDelegateClass
  delegateObj.addUIImage("yourstring")
}

También para despacho después de la cola principal

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
  // your code here
}

Reemplace YourAppDelegateClass por delegar la clase

 396
Author: codester,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-04-20 09:18:14

Swift 3 & Swift 4 versión:

DispatchQueue.main.async {
    print("Hello")
}

Swift3 y XCode 9.2:

dispatch_async_on_main_queue {
     //Your code
     print("Hello")
 }
 59
Author: DazChong,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-05-17 05:42:01

Swift 2

Usando Cierres finales esto se convierte en:

dispatch_async(dispatch_get_main_queue()) {
    self.tableView.reloadData()
}

Los cierres finales son un azúcar sintáctico rápido que permite definir el cierre fuera del ámbito del parámetro de función. Para obtener más información, consulte Cierres finales en la Guía del Lenguaje de programación Swift 2.2.

En el caso dispatch_async la API es func dispatch_async(queue: dispatch_queue_t, _ block: dispatch_block_t) ya que dispatch_block_t es un alias de tipo para () -> Void - Un cierre que recibe 0 parámetros y no tiene un valor devuelto, y el bloque es el último parámetro de la función podemos definir el cierre en el ámbito exterior de dispatch_async.

 14
Author: Maxim Veksler,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-09-25 19:06:10

Aquí está la sintaxis de estilo Swifty / Cocoa más agradable (IMO) para lograr el mismo resultado que las otras respuestas:

NSOperationQueue.mainQueue().addOperationWithBlock({
    // Your code here
})

O puedes tomar la popular biblioteca Swift Async para aún menos código y más funcionalidad:

Async.main {
    // Your code here
}
 5
Author: pejalo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-06-13 06:12:02

La forma correcta de hacer esto es usar dispatch_async en main_queue, como hice en el siguiente código

dispatch_async(dispatch_get_main_queue(), {
                        (self.delegate as TBGQRCodeViewController).displayQRCode(receiveAddr, withAmountInBTC:amountBTC)
                        })
 3
Author: almel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-04-07 17:54:16

Aquí hay una pequeña función global que puede agregar para una sintaxis más agradable:

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

Y uso

dispatch_on_main {
    // Do some UI stuff
}
 2
Author: Mateusz Grzegorzek,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-04-26 11:58:23

No te olvides de debilitarte a ti mismo si estás usando a ti mismo dentro del cierre.

dispatch_async(dispatch_get_main_queue(),{ [weak self] () -> () in
            if let strongSelf = self {
                self?.doSomething()
            }
        })
 1
Author: villy393,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-02-15 15:25:59

Reload collectionView on Main Thread

 DispatchQueue.main.async {
                self.collectionView.reloadData()
            }
 -1
Author: Sanjay Mali,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-10 11:21:57