dispatch_after – GCD en swift?

He revisado el iBook de Apple y no encontré ninguna definición de él:

¿Alguien puede explicar la estructura de dispatch_after ?

 dispatch_after(, , ) 

Una idea más clara de la estructura:

 dispatch_after(when: dispatch_time_t, queue: dispatch_queue_t, block: dispatch_block_t?) 

dispatch_time_t es un UInt64 . El dispatch_queue_t realidad es un tipo de alias para un NSObject , pero solo debe usar sus métodos familiares de GCD para obtener colas. El bloque es un cierre de Swift. Específicamente, dispatch_block_t se define como () -> Void , que es equivalente a () -> () .

Ejemplo de uso:

 let delayTime = dispatch_time(DISPATCH_TIME_NOW, Int64(1 * Double(NSEC_PER_SEC))) dispatch_after(delayTime, dispatch_get_main_queue()) { print("test") } 

EDITAR:

Recomiendo usar la función de delay muy agradable de @ matt .

EDICION 2:

En Swift 3, habrá nuevos contenedores para GCD. Vea aquí: https://github.com/apple/swift-evolution/blob/master/proposals/0088-libdispatch-for-swift3.md

El ejemplo original se escribiría de la siguiente manera en Swift 3:

 let deadlineTime = DispatchTime.now() + .seconds(1) DispatchQueue.main.asyncAfter(deadline: deadlineTime) { print("test") } 

Tenga en cuenta que puede escribir la statement deadlineTime como DispatchTime.now() + 1.0 y obtener el mismo resultado porque el operador + se reemplaza de la siguiente manera (de manera similar para - ):

  • func +(time: DispatchTime, seconds: Double) -> DispatchTime
  • func +(time: DispatchWalltime, interval: DispatchTimeInterval) -> DispatchWalltime

Esto significa que si no usa la enum DispatchTimeInterval y solo escribe un número, se supone que está utilizando segundos.

Uso dispatch_after tan seguido que escribí una función de utilidad de nivel superior para simplificar la syntax:

 func delay(delay:Double, closure:()->()) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), closure) } 

Y ahora puedes hablar así:

 delay(0.4) { // do stuff } 

Guau, un lenguaje donde puedes mejorar el idioma. ¿Que podría ser mejor?


Actualización para Swift 3, Xcode 8 Seed 6

Parece que no vale la pena preocuparse, ahora que han mejorado la syntax de las llamadas:

 func delay(_ delay:Double, closure:@escaping ()->()) { let when = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: when, execute: closure) } 

Para ampliar la respuesta de Cezary, que se ejecutará después de 1 nanosegundo, tuve que hacer lo siguiente para ejecutar después de 4 segundos y medio.

  let delay = 4.5 * Double(NSEC_PER_SEC) let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay)) dispatch_after(time, dispatch_get_main_queue(), block) 

Editar: descubrí que mi código original era un poco erróneo. La tipificación implícita causa un error de comstackción si no convierte NSEC_PER_SEC en un doble.

Si alguien puede sugerir una solución más óptima, estaría ansioso por escucharla.

== Actualización para Swift 3 ==

Esto es súper fácil y elegante en Swift 3:

  DispatchQueue.main.asyncAfter(deadline: .now() + 4.5) { // ... } 

La syntax de Matt es muy buena y si necesita invalidar el bloque, puede usar esto:

 typealias dispatch_cancelable_closure = (cancel : Bool) -> Void func delay(time:NSTimeInterval, closure:()->Void) -> dispatch_cancelable_closure? { func dispatch_later(clsr:()->Void) { dispatch_after( dispatch_time( DISPATCH_TIME_NOW, Int64(time * Double(NSEC_PER_SEC)) ), dispatch_get_main_queue(), clsr) } var closure:dispatch_block_t? = closure var cancelableClosure:dispatch_cancelable_closure? let delayedClosure:dispatch_cancelable_closure = { cancel in if closure != nil { if (cancel == false) { dispatch_async(dispatch_get_main_queue(), closure!); } } closure = nil cancelableClosure = nil } cancelableClosure = delayedClosure dispatch_later { if let delayedClosure = cancelableClosure { delayedClosure(cancel: false) } } return cancelableClosure; } func cancel_delay(closure:dispatch_cancelable_closure?) { if closure != nil { closure!(cancel: true) } } 

Úselo como sigue

 let retVal = delay(2.0) { println("Later") } delay(1.0) { cancel_delay(retVal) } 

créditos

El enlace de arriba parece estar abajo. Código Objc original de Github

Apple tiene un snippet dispatch_after para Objective-C :

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(<#delayInSeconds#> * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ <#code to be executed after a specified delay#> }); 

Aquí está el mismo fragmento portado a Swift 3:

 DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + <#delayInSeconds#>) { <#code to be executed after a specified delay#> } 

La solución más simple en Swift 3.0 y Swift 4.0

 func delayWithSeconds(_ seconds: Double, completion: @escaping () -> ()) { DispatchQueue.main.asyncAfter(deadline: .now() + seconds) { completion() } } 

Uso

 delayWithSeconds(1) { //Do something } 

Otra forma es extender Doble como este:

 extension Double { var dispatchTime: dispatch_time_t { get { return dispatch_time(DISPATCH_TIME_NOW,Int64(self * Double(NSEC_PER_SEC))) } } } 

Entonces puedes usarlo así:

 dispatch_after(Double(2.0).dispatchTime, dispatch_get_main_queue(), { () -> Void in self.dismissViewControllerAnimated(true, completion: nil) }) 

Me gusta la función de retraso de Matt, pero por preferencia preferiría limitar el paso de cierres.

En Swift 3.0

Colas de envío

  DispatchQueue(label: "test").async { //long running Background Task for obj in 0...1000 { print("async \(obj)") } // UI update in main queue DispatchQueue.main.async(execute: { print("UI update on main queue") }) } DispatchQueue(label: "m").sync { //long running Background Task for obj in 0...1000 { print("sync \(obj)") } // UI update in main queue DispatchQueue.main.sync(execute: { print("UI update on main queue") }) } 

Despacho después de 5 segundos

  DispatchQueue.main.after(when: DispatchTime.now() + 5) { print("Dispatch after 5 sec") } 

1) Agregue este método como parte de la extensión UIViewController.

 extension UIViewController{ func runAfterDelay(delay: NSTimeInterval, block: dispatch_block_t) { let time = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) dispatch_after(time, dispatch_get_main_queue(), block) } } 

Llamar a este método en VC:

  self.runAfterDelay(5.0, block: { //Add code to this block print("run After Delay Success") }) 

2) performSelector (“yourMethod Name”, withObject: nil, afterDelay: 1)

3)

 override func viewWillAppear(animated: Bool) { dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue(), { () -> () in //Code Here }) 

// Formulario compacto

 dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2), dispatch_get_main_queue()) { //Code here } 

}

Versión de Swift 3.0

Después de la función de cierre ejecutar algunas tareas después de la demora en el hilo principal.

 func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } 

Llame a esta función como:

 performAfterDelay(delay: 4.0) { print("test") } 

Aunque no es la pregunta original del OP, ciertas preguntas relacionadas con NSTimer se han marcado como duplicados de esta pregunta, por lo que vale la pena incluir una respuesta NSTimer aquí.

NSTimer vs dispatch_after

  • NSTimer es más alto nivel mientras dispatch_after es más bajo nivel.
  • NSTimer es más fácil de cancelar. La cancelación de dispatch_after requiere escribir más código .

Retrasando una tarea con NSTimer

Crea una instancia NSTimer .

 var timer = NSTimer() 

Comience el temporizador con la demora que necesita.

 // invalidate the timer if there is any chance that it could have been called before timer.invalidate() // delay of 2 seconds timer = NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 

Agregue una función para llamar después de la demora (usando el nombre que utilizó para el parámetro selector anterior).

 func delayedAction() { print("Delayed action has now started." } 

Notas

  • Si necesita cancelar la acción antes de que ocurra, simplemente llame a timer.invalidate() .
  • Para una acción repetida use repeats: true .
  • Si tiene un evento de una vez sin necesidad de cancelar, entonces no hay necesidad de crear la variable de instancia del timer . Lo siguiente será suficiente:

     NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false) 
  • Vea mi respuesta más completa aquí .

Otro ayudante para retrasar su código que es 100% Swift en el uso y, opcionalmente, permite elegir un hilo diferente para ejecutar su código retrasado de:

 public func delay(bySeconds seconds: Double, dispatchLevel: DispatchLevel = .main, closure: @escaping () -> Void) { let dispatchTime = DispatchTime.now() + seconds dispatchLevel.dispatchQueue.asyncAfter(deadline: dispatchTime, execute: closure) } public enum DispatchLevel { case main, userInteractive, userInitiated, utility, background var dispatchQueue: DispatchQueue { switch self { case .main: return DispatchQueue.main case .userInteractive: return DispatchQueue.global(qos: .userInteractive) case .userInitiated: return DispatchQueue.global(qos: .userInitiated) case .utility: return DispatchQueue.global(qos: .utility) case .background: return DispatchQueue.global(qos: .background) } } } 

Ahora simplemente demora su código en el hilo principal como este:

 delay(bySeconds: 1.5) { // delayed code } 

Si desea retrasar su código a un hilo diferente :

 delay(bySeconds: 1.5, dispatchLevel: .background) { // delayed code that will run on background thread } 

Si prefiere un Framework que también tenga algunas características más útiles, realice la compra de HandySwift . Puede agregarlo a su proyecto a través de Cartago y luego usarlo exactamente como en los ejemplos anteriores, por ejemplo:

 import HandySwift delay(bySeconds: 1.5) { // delayed code } 

Esto funcionó para mí.

Swift 3:

 let time1 = 8.23 let time2 = 3.42 // Delay 2 seconds DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) { print("Sum of times: \(time1 + time2)") } 

C objective:

 CGFloat time1 = 3.49; CGFloat time2 = 8.13; // Delay 2 seconds dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ CGFloat newTime = time1 + time2; NSLog(@"New time: %f", newTime); }); 

Siempre prefiero usar la extensión en lugar de las funciones gratuitas.

Swift 4

 public extension DispatchQueue { private class func delay(delay: TimeInterval, closure: @escaping () -> Void) { let when = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: when, execute: closure) } class func performAction(after seconds: TimeInterval, callBack: @escaping (() -> Void) ) { DispatchQueue.delay(delay: seconds) { callBack() } } } 

Use como sigue.

 DispatchQueue.performAction(after: 0.3) { // Code Here } 

Swift 3 y 4:

Puede crear una extensión en DispatchQueue y agregar el retraso de la función que usa DispatchQueue asyncDespués de la función internamente

 extension DispatchQueue { static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) { let timeInterval = DispatchTime.now() + delay DispatchQueue.main.asyncAfter(deadline: timeInterval, execute: closure) } } 

utilizar:

 DispatchQueue.delay(.seconds(1)) { print("This is after delay") } 

Retrasando la llamada de GCD usando asyncAfter in swift

 let delayQueue = DispatchQueue(label: "com.theappmaker.in", qos: .userInitiated) let additionalTime: DispatchTimeInterval = .seconds(2) 

Podemos retrasar como ** microsegundos , milisegundos , nanosegundos

 delayQueue.asyncAfter(deadline: .now() + 0.60) { print(Date()) } delayQueue.asyncAfter(deadline: .now() + additionalTime) { print(Date()) } 

Para múltiples funciones usa esto. Esto es muy útil para usar animaciones o el cargador de actividades para funciones estáticas o cualquier actualización de UI.

 DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { // Call your function 1 DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // Call your function 2 } } 

Por ejemplo, use una animación antes de que se vuelva a cargar tableView. O cualquier otra actualización de UI después de la animación.

 *// Start your amination* self.startAnimation() DispatchQueue.main.asyncAfter(deadline: .now() + 0.9) { *// The animation will execute depending on the delay time* self.stopAnimation() DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { *// Now update your view* self.fetchData() self.updateUI() } } 

use este código para realizar alguna tarea relacionada con la interfaz de usuario después de 2.0 segundos.

  let delay = 2.0 let delayInNanoSeconds = dispatch_time(DISPATCH_TIME_NOW, Int64(delay * Double(NSEC_PER_SEC))) let mainQueue = dispatch_get_main_queue() dispatch_after(delayInNanoSeconds, mainQueue, { print("Some UI related task after delay") }) 

Versión de Swift 3.0

Después de la función de cierre ejecutar algunas tareas después de la demora en el hilo principal.

 func performAfterDelay(delay : Double, onCompletion: @escaping() -> Void){ DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + delay, execute: { onCompletion() }) } 

Llame a esta función como:

 performAfterDelay(delay: 4.0) { print("test") } 

Ahora más que azúcar sintáctica para despachos asincrónicos en Grand Central Dispatch (GCD) en Swift.

agregar Podfile

 pod 'AsyncSwift' 

Entonces, puedes usarlo así.

 let seconds = 3.0 Async.main(after: seconds) { print("Is called after 3 seconds") }.background(after: 6.0) { print("At least 3.0 seconds after previous block, and 6.0 after Async code is called") } 

Swift 4 tiene una forma bastante corta de hacer esto:

 Timer.scheduledTimer(withTimeInterval: 2, repeats: false) { (timer) in // Your stuff here print("hello") } 

dispatch_after (dispatch_time (DISPATCH_TIME_NOW, (int64_t) (10 * NSEC_PER_SEC)), dispatch_get_main_queue (), ^ {// …});

La función dispatch_after ( :: _ 🙂 toma tres parámetros:

un retraso de una cola de envío un bloque o cierre La función dispatch_after ( :: _ 🙂 invoca el bloque o cierre en la cola de envío que se pasa a la función después de un retraso determinado. Tenga en cuenta que el retraso se crea utilizando la función dispatch_time ( : :). Recuerde esto porque también usamos esta función en Swift.

Recomiendo ir a través del tutorial Raywenderlich Dispatch tutorial