¿Cómo crear un retraso en Swift?
Quiero pausar mi aplicación en un punto determinado. En otras palabras, quiero que mi aplicación ejecute el código, pero luego, en cierto punto, haga una pausa de 4 segundos y luego continúe con el resto del código. ¿Cómo puedo hacer esto?
Estoy usando Swift.
En la mayoría de los casos , usar un dispatch_after
bloque es mejor que usarlo, sleep(time)
ya que el hilo en el que se realiza el sueño no puede realizar otro trabajo. cuando se utiliza, dispatch_after
el hilo en el que se trabaja no se bloquea, por lo que puede realizar otro trabajo mientras tanto.
Si está trabajando en el hilo principal de su aplicación, su uso sleep(time)
es malo para la experiencia del usuario de su aplicación, ya que la interfaz de usuario no responde durante ese tiempo.
Dispatch after programa la ejecución de un bloque de código en lugar de congelar el hilo:
Rápido ≥ 3,0
let seconds = 4.0
DispatchQueue.main.asyncAfter(deadline: .now() + seconds) {
// Put your code which should be executed with a delay here
}
Swift ≥ 5,5 en un contexto asíncrono:
func foo() async {
try await Task.sleep(nanoseconds: UInt64(seconds * Double(NSEC_PER_SEC)))
// Put your code which should be executed with a delay here
}
Rápido < 3.0
let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 4 * Int64(NSEC_PER_SEC))
dispatch_after(time, dispatch_get_main_queue()) {
// Put your code which should be executed with a delay here
}
En lugar de una suspensión, que bloqueará su programa si se llama desde el hilo de la interfaz de usuario, considere usar NSTimer
o un temporizador de envío.
Pero, si realmente necesitas un retraso en el hilo actual:
do {
sleep(4)
}
Esto utiliza la sleep
función de UNIX.
Comparación entre diferentes enfoques en Swift 3.0
1. Dormir
Este método no tiene devolución de llamada. Coloque los códigos directamente después de esta línea para que se ejecuten en 4 segundos. Evitará que el usuario itere con elementos de la interfaz de usuario como el botón de prueba hasta que se acabe el tiempo. Aunque el botón está un poco congelado cuando comienza el sueño, otros elementos, como el indicador de actividad, siguen girando sin congelarse. No puedes volver a activar esta acción mientras duermes.
sleep(4)
print("done")//Do stuff here
2. Envío, ejecución y cronómetro
Estos tres métodos funcionan de manera similar, todos se ejecutan en un subproceso en segundo plano con devoluciones de llamadas, solo que con una sintaxis diferente y características ligeramente diferentes.
El envío se usa comúnmente para ejecutar algo en el hilo en segundo plano. Tiene la devolución de llamada como parte de la llamada a la función.
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
print("done")
})
Realizar es en realidad un cronómetro simplificado. Configura un temporizador con retraso y luego activa la función mediante el selector.
perform(#selector(callback), with: nil, afterDelay: 4.0)
func callback() {
print("done")
}}
Y, por último, el temporizador también ofrece la posibilidad de repetir la devolución de llamada, lo cual no es útil en este caso.
Timer.scheduledTimer(timeInterval: 4, target: self, selector: #selector(callback), userInfo: nil, repeats: false)
func callback() {
print("done")
}}
Para estos tres métodos, cuando hace clic en el botón para activarlos, la interfaz de usuario no se congelará y podrá hacer clic en ella nuevamente. Si vuelve a hacer clic en el botón, se configurará otro temporizador y la devolución de llamada se activará dos veces.
En conclusión
Ninguno de los cuatro métodos funciona lo suficientemente bien por sí solo. sleep
deshabilitará la interacción del usuario, por lo que la pantalla " se congela " (en realidad no) y resulta en una mala experiencia del usuario. Los otros tres métodos no congelarán la pantalla, pero puedes activarlos varias veces y, la mayoría de las veces, querrás esperar hasta recibir la llamada antes de permitir que el usuario vuelva a realizar la llamada.
Por lo tanto, un mejor diseño utilizará uno de los tres métodos asíncronos con bloqueo de pantalla. Cuando el usuario hace clic en el botón, cubra toda la pantalla con una vista translúcida con un indicador de actividad giratorio en la parte superior, que le indica al usuario que se está manejando el clic en el botón. Luego elimine la vista y el indicador en la función de devolución de llamada, indicando al usuario que la acción se manejó correctamente, etc.
En Swift 4.2 y Xcode 10.1
Tienes 4 formas en total de retrasar. De estas opciones, es preferible llamar o ejecutar una función después de un tiempo. Sleep () es el caso que menos se utiliza.
Opción 1.
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
self.yourFuncHere()
}
//Your function here
func yourFuncHere() {
}
Opcion 2.
perform(#selector(yourFuncHere2), with: nil, afterDelay: 5.0)
//Your function here
@objc func yourFuncHere2() {
print("this is...")
}
Opción 3.
Timer.scheduledTimer(timeInterval: 5.0, target: self, selector: #selector(yourFuncHere3), userInfo: nil, repeats: false)
//Your function here
@objc func yourFuncHere3() {
}
Opción 4.
sleep(5)
Si desea llamar a una función después de un tiempo para ejecutar algo, no use la suspensión .
Estoy de acuerdo con Palle en que usar dispatch_after
es una buena opción aquí. Pero probablemente no te gusten las llamadas de GCD porque son bastante molestas de escribir . En su lugar, puedes agregar esta útil ayuda :
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 un hilo en segundo plano como este:
delay(bySeconds: 1.5, dispatchLevel: .background) {
// delayed code that will run on background thread
}
Retrasar el código en el hilo principal es aún más sencillo:
delay(bySeconds: 1.5) {
// delayed code, by default run in main thread
}
Si prefiere un Framework que también tenga algunas funciones más útiles, consulte HandySwift . Puedes agregarlo a tu proyecto a través de SwiftPM y luego usarlo exactamente como en los ejemplos anteriores:
import HandySwift
delay(by: .seconds(1.5)) {
// delayed code
}