ios - grand - nsoperation swift
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 quedispatch_after
es un nivel más bajo. -
NSTimer
es más fácil de cancelar. Cancelardispatch_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)
}
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")
}