¿Cómo crear un retraso en Swift?

Resuelto Schuey999 asked hace 54 años • 19 respuestas

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.

Schuey999 avatar Jan 01 '70 08:01 Schuey999
Aceptado

En la mayoría de los casos , usar un dispatch_afterbloque 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_afterel 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
}
Palle avatar Sep 21 '2015 13:09 Palle

En lugar de una suspensión, que bloqueará su programa si se llama desde el hilo de la interfaz de usuario, considere usar NSTimero un temporizador de envío.

Pero, si realmente necesitas un retraso en el hilo actual:

do {
    sleep(4)
}

Esto utiliza la sleepfunción de UNIX.

nneonneo avatar Dec 17 '2014 02:12 nneonneo

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

ingrese la descripción de la imagen aquí

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.

ingrese la descripción de la imagen aquí

En conclusión

Ninguno de los cuatro métodos funciona lo suficientemente bien por sí solo. sleepdeshabilitará 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.

Fangming avatar Jul 13 '2017 03:07 Fangming

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 .

Naresh avatar Feb 12 '2019 06:02 Naresh

Estoy de acuerdo con Palle en que usar dispatch_afteres 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
}
Jeehut avatar Jun 09 '2016 17:06 Jeehut