threads grand gcd dispatchqueue dispatch_async central async ios swift grand-central-dispatch

ios - grand - nsoperation swift



dispatch_after-GCD en swift? (22)

He iBook el iBook de Apple y no pude encontrar ninguna definición:

¿Alguien puede explicar la estructura de dispatch_after ?

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


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) } }

Llame 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 })

// Forma compacta

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

}


Ahora más que azúcar sintáctico para despachos asíncronos en Grand Central Dispatch (GCD) en Swift.

añadir 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") }


Apple tiene un fragmento 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#> }


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 un nivel más alto, mientras que dispatch_after es un nivel más bajo.
  • NSTimer es más fácil de cancelar. Cancelar dispatch_after requiere escribir más código .

Retrasando una tarea con NSTimer

Crear una instancia de NSTimer .

var timer = NSTimer()

Arranca el temporizador con la demora que necesites.

// 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 del retraso (usando el nombre que usó para el parámetro de 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 único sin necesidad de cancelar, entonces no es necesario crear la variable de instancia del timer . Bastará con lo siguiente:

    NSTimer.scheduledTimerWithTimeInterval(2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)

  • Vea mi respuesta más completa here .


En Swift 4

Utilice este fragmento de código:

let delayInSec = 1.0 DispatchQueue.main.asyncAfter(deadline: .now() + delayInSec) { // code here print("It works") }


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 objetivo:

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); });


Otra forma es extender el doble de esta manera:

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 retardo de Matt, pero por preferencia prefiero limitar los cierres de paso.


Otro ayudante para retrasar su código es 100% rápido en uso y, opcionalmente, permite elegir un hilo diferente para ejecutar su código retrasado desde:

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 retrasas tu código en el hilo principal de esta manera:

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 prefieres un Framework que también tenga algunas funciones más útiles, entonces selecciona 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 }


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)

Edición: descubrí que mi código original era un poco incorrecto. La escritura implícita provoca un error de compilación si no convierte NSEC_PER_SEC en un Double.

Si alguien puede sugerir una solución más óptima, me gustaría escucharla.

== Actualización para Swift 3 ==

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

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


Swift 4 tiene una forma bastante corta de hacer esto:

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


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 es en realidad un alias de tipo para un NSObject , pero solo debes usar tus métodos GCD familiares para obtener colas. El bloque es un cierre 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 delay .

EDIT 2:

En Swift 3, habrá nuevos envoltorios para GCD. Consulte 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 declaración 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 simplemente escribe un número, se supone que está usando segundos.


Uso dispatch_after tan a menudo que escribí una función de utilidad de nivel superior para simplificar la sintaxis:

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 }

Wow, 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 molestarse, ahora que han mejorado la sintaxis de las llamadas:

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


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 una cola de envío un bloque o cierre La función dispatch_after ( :: _ :) invoca el bloqueo 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 ( : :). Recuerda esto porque también usamos esta función en Swift.

Recomiendo ir a través del tutorial Raywenderlich Dispatch tutorial


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 Swift 3.0

La siguiente función de cierre ejecuta alguna tarea tras retraso 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") }


La sintaxis de matt es muy buena y si necesitas invalidar el bloqueo, puedes 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) } }

Usar como sigue

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

credits

El enlace de arriba parece estar caído. Código Objc original de Github


En Swift 3.0

Colas de despacho

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") }


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 }


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 una tableView. O cualquier otra actualización de la interfaz de usuario 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() } }


Retrasar la llamada GCD usando asyncAfter en swift

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

Podemos retrasar hasta ** microsegundos , milisegundos , nanosegundos.

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


Siempre prefiero usar extensión en lugar de 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 un retardo de función que use la función AsyncAfter de DispatchQueue 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") }


Versión Swift 3.0

La siguiente función de cierre ejecuta alguna tarea tras retraso 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") }