¿Cómo puedo usar Timer (anteriormente NSTimer) en Swift?


257

Lo intenté

var timer = NSTimer()
timer(timeInterval: 0.01, target: self, selector: update, userInfo: nil, repeats: false)

Pero recibí un error diciendo

'(timeInterval: $T1, target: ViewController, selector: () -> (), userInfo: NilType, repeats: Bool) -> $T6' is not identical to 'NSTimer'

1
"¿Cómo puedo usar NSTimer en Swift?" - De la misma manera que lo usa en Objective-C. Su API no cambió.
— El cruasán paramagnético

Respuestas:


535

Esto funcionará:

override func viewDidLoad() {
    super.viewDidLoad()
    // Swift block syntax (iOS 10+)
    let timer = Timer(timeInterval: 0.4, repeats: true) { _ in print("Done!") }
    // Swift >=3 selector syntax
    let timer = Timer.scheduledTimer(timeInterval: 0.4, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)
    // Swift 2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
    // Swift <2.2 selector syntax
    let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
}

// must be internal or public. 
@objc func update() {
    // Something cool
}

Para Swift 4, el método del que desea obtener el selector debe estar expuesto a Objective-C, por lo tanto, el @objcatributo debe agregarse a la declaración del método.


2
Agregaría que la clase con estos métodos debe ser un NSObject, de lo contrario terminará con un error de selector no reconocido
— Joshua

27
A partir de Xcode 6.1, tuve que agregar "@objc" al encabezado de la función de esta manera: "@objc func update () {". Sin ella, la aplicación se bloquea en el primer incendio.
— kev

Puedes declarar Var timer: NSTimer! inicialmente y úselo cuando sea necesario!
— Nigilan

1
Una versión quizás más útil de la sintaxis de bloque: let timer = Timer.scheduledTimer (withTimeInterval: timeout, repits: false) {_ in print ("Done.")}
— Teo Sartori

No puede usar 'let timer = Timer (timeInterval: 0.4, repeats: true) {_ in print ("Done!")}' Esto no iniciará el temporizador y no podrá hacer que se repita. Debe usar Timer.scheduledTimer.
— Siamaster

149

Evento repetido

Puede usar un temporizador para realizar una acción varias veces, como se ve en el siguiente ejemplo. El temporizador llama a un método para actualizar una etiqueta cada medio segundo.

ingrese la descripción de la imagen aquí

Aquí está el código para eso:

import UIKit

class ViewController: UIViewController {

    var counter = 0
    var timer = Timer()

    @IBOutlet weak var label: UILabel!

    // start timer
    @IBAction func startTimerButtonTapped(sender: UIButton) {
        timer.invalidate() // just in case this button is tapped multiple times

        // start the timer
        timer = Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(timerAction), userInfo: nil, repeats: true)
    }

    // stop timer
    @IBAction func cancelTimerButtonTapped(sender: UIButton) {
        timer.invalidate()
    }

    // called every time interval from the timer
    func timerAction() {
        counter += 1
        label.text = "\(counter)"
    }
}

Evento retrasado

También puede usar un temporizador para programar un evento único durante algún tiempo en el futuro. La principal diferencia con el ejemplo anterior es que usa en repeats: falselugar de true.

timer = Timer.scheduledTimer(timeInterval: 2.0, target: self, selector: #selector(delayedAction), userInfo: nil, repeats: false)

El ejemplo anterior llama a un método llamado delayedActiondos segundos después de que se establece el temporizador. No se repite, pero aún puede llamartimer.invalidate() si necesita cancelar el evento antes de que ocurra.

Notas

  • Si existe alguna posibilidad de iniciar su instancia del temporizador varias veces, asegúrese de invalidar primero la instancia del temporizador anterior. De lo contrario, perderá la referencia al temporizador y ya no podrá detenerlo. (ver estas preguntas y respuestas )
  • No use temporizadores cuando no sean necesarios. Consulte la sección de temporizadores de la Guía de eficiencia energética para aplicaciones iOS .

Relacionado


1
@raddevus, gracias por hacérmelo saber. Eliminé el viejo comentario de Swift 3.
— Suragch

31

Actualizado a Swift 4, aprovechando userInfo:

class TimerSample {

    var timer: Timer?

    func startTimer() {
        timer = Timer.scheduledTimer(timeInterval: 5.0,
                                     target: self,
                                     selector: #selector(eventWith(timer:)),
                                     userInfo: [ "foo" : "bar" ],
                                     repeats: true)
    }

    // Timer expects @objc selector
    @objc func eventWith(timer: Timer!) {
        let info = timer.userInfo as Any
        print(info)
    }

}

2
Muestre un ejemplo de trabajo, qué significa "personalizado" y "datos" si la función espera un NSTimerobjeto
— Carlos.V

1
Realmente no importa. Puede almacenar cualquier cosa que necesite en el diccionario userInfo, en este caso es un par arbitrario de clave-valor.
— igraczech

Esto es útil, pero se rompió en Swift 3, ejemplo de trabajo: Timer.scheduledTimer (timeInterval: 1.0, target: self, selector: #selector (event), userInfo: "Info Sent", repite: true)
— Bobby

28

A partir de iOS 10, también hay un nuevo método de fábrica de temporizador basado en bloques que es más limpio que usar el selector:

    _ = Timer.scheduledTimer(withTimeInterval: 5, repeats: false) { timer in
        label.isHidden = true
    }

1
De la forma en que lo estás haciendo, ¿no sería mejor eliminarlo _ = y comenzar Timer?
— Miel

2
Puede omitir _ = si silencia la advertencia sobre el valor no utilizado o si simplemente no le importan las advertencias. No me gusta verificar el código con advertencias.
— Josh Homann

22

Swift 3, pre iOS 10

func schedule() {
    DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(timeInterval: 20, target: self,
                                   selector: #selector(self.timerDidFire(timer:)), userInfo: nil, repeats: false)
    }
  }

  @objc private func timerDidFire(timer: Timer) {
    print(timer)
  }

Swift 3, iOS 10+

DispatchQueue.main.async {
      self.timer = Timer.scheduledTimer(withTimeInterval: 20, repeats: false) { timer in
        print(timer)
      }
    }

Notas

  • Tiene que estar en la cola principal.
  • La función de devolución de llamada puede ser pública, privada, ...
  • La función de devolución de llamada debe ser @objc

1
Entiendo que solo la devolución de llamada del temporizador debe estar en la cola principal y que lo siguiente sería un poco más eficiente: self.timer = Timer.scheduledTimer (withTimeInterval: 20, repite: false) {timer en DispatchQueue.main.async {print (temporizador)}}
— Mathieu Frenette

Mi temporizador no se desencadena a partir de una de mis objetos y que hizo el truco :)
— Reimond Colina

@ReimondHill Necesitas cambiartimeInterval
— onmyway133

17

Comprueba con:

Swift 2

var timer = NSTimer.scheduledTimerWithTimeInterval(0.01, target: self, selector: Selector("update"), userInfo: nil, repeats: true)

Swift 3, 4, 5

var timer = Timer.scheduledTimer(timeInterval: 0.01, target: self, selector: #selector(self.update), userInfo: nil, repeats: true)

2
Ya lo intenté pero dice 'No se pudo encontrar una sobrecarga para' init 'que acepte los argumentos proporcionados'
— user3225917

1
Lo mismo aquí, recibí el error 'No se pudo encontrar una sobrecarga para' init 'que acepta los argumentos proporcionados'. ¿Esta línea realmente funciona?
— Yangshun Tay

Me sale el mismo error que @yangshun. ¿Qué tipo de objeto debe selfser? UIView está bien?
— SimplGy

@SimpleAsCouldBe: sí, eso está bien
— Midhun MP

func amountSubmitSuccess () {self.view.hideToastActivity () self.view.makeToast (mensaje: "The Amount Successful Registered") var timer = NSTimer.scheduledTimerWithTimeInterval (0.5, target: self, selector: "moveToBidderPage", userInfo: nil, repite: false)} func moveToBidderPage () {let loginPageView = self.storyboard? .instantiateViewControllerWithIdentifier ("bidderpageID") como! BidderPage self.navigationController? .PushViewController (loginPageView, animado: verdadero)}
— AG

11

Deberá usar el temporizador en lugar del NSTimer en Swift 3.

Aquí hay un ejemplo:

Timer.scheduledTimer(timeInterval: 1, 
    target: self, 
    selector: #selector(YourController.update), 
    userInfo: nil, 
    repeats: true)

// @objc selector expected for Timer
@objc func update() {
    // do what should happen when timer triggers an event
}

11

Swift 5

Personalmente prefiero el temporizador con el cierre de bloque:

    Timer.scheduledTimer(withTimeInterval: 1, repeats: false) { (_) in
       // TODO: - whatever you want
    }

Tenga en cuenta que esto solo está disponible en macOS 10.12 o posterior. No estoy seguro acerca de ios.
— jeff-h

También está disponible en iOS.
— Wissa

7

para swift 3 y Xcode 8.2 (es bueno tener bloques, pero si compila para iOS9 Y desea información de usuario):

...

        self.timer = Timer(fireAt: fire,
                           interval: deltaT,
                           target: self,
                           selector: #selector(timerCallBack(timer:)),
                           userInfo: ["custom":"data"],
                           repeats: true)

        RunLoop.main.add(self.timer!, forMode: RunLoopMode.commonModes)
        self.timer!.fire()
}

func timerCallBack(timer: Timer!){
        let info = timer.userInfo
        print(info)
    }

6

Temporizador simple (Swift 3.1)

¿Por qué?

Esta es una clase de temporizador simple en Swift que le permite:

  • Temporizador de alcance local
  • Encadenable
  • Uno liners
  • Use devoluciones de llamada regulares

Uso:

SimpleTimer(interval: 3,repeats: true){print("tick")}.start()//Ticks every 3 secs

Código:

class SimpleTimer {/*<--was named Timer, but since swift 3, NSTimer is now Timer*/
    typealias Tick = ()->Void
    var timer:Timer?
    var interval:TimeInterval /*in seconds*/
    var repeats:Bool
    var tick:Tick

    init( interval:TimeInterval, repeats:Bool = false, onTick:@escaping Tick){
        self.interval = interval
        self.repeats = repeats
        self.tick = onTick
    }
    func start(){
        timer = Timer.scheduledTimer(timeInterval: interval, target: self, selector: #selector(update), userInfo: nil, repeats: true)//swift 3 upgrade
    }
    func stop(){
        if(timer != nil){timer!.invalidate()}
    }
    /**
     * This method must be in the public or scope
     */
    @objc func update() {
        tick()
    }
}

¿Cómo detener el temporizador dentro de ese bloque en algunas condiciones?
— Desarrollador móvil iOS Android

Simplemente almacene la referencia al temporizador en una clase y luego simplemente llame a stop. El compilador Xcode le dirá si necesita escapar etc.
— eonist

3
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Y crea diversión por el nombre createEnemy

fund createEnemy ()
{
do anything ////
}

3

Primero declara tu temporizador

var timer: Timer?

Luego agregue una línea en viewDidLoad () o en cualquier función que desee iniciar el temporizador

timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(action), userInfo: nil, repeats: false)

Esta es la función a la que devolverá la llamada para hacer algo que debe ser @objc

@objc func action () {
print("done")
}

2

En Swift 3 algo así con @objc:

func startTimerForResendingCode() {
    let timerIntervalForResendingCode = TimeInterval(60)
    Timer.scheduledTimer(timeInterval: timerIntervalForResendingCode,
                         target: self,
                         selector: #selector(timerEndedUp),
                         userInfo: nil,
                         repeats: false)
}




@objc func timerEndedUp() {
    output?.timerHasFinishedAndCodeMayBeResended()
}

1

Si inicia el método del temporizador

let timer = Timer(timeInterval: 3, target: self, selector: #selector(update(_:)), userInfo: [key : value], repeats: false)

func update(_ timer : Timer) {

}

luego agréguelo al bucle usando el método que no se llamará a otro selector

RunLoop.main.add(timer!, forMode: .defaultRunLoopMode)

NOTA: Si desea que esto se repita, haga que las repeticiones sean verdaderas y mantenga la referencia del temporizador; de lo contrario, no se llamará al método de actualización.

Si estás usando este método.

Timer.scheduledTimer(timeInterval: seconds, target: self, selector: #selector(update(_:)), userInfo: nil, repeats: true)

mantenga una referencia para su uso posterior si las repeticiones son verdaderas.


0

Traté de hacer en una clase NSObject y esto funcionó para mí:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(300)) {  
print("Bang!") }

-2

NSTimer ha cambiado de nombre a Timer en Swift 4.2. esta sintaxis funcionará en 4.2:

let timer = Timer.scheduledTimer(timeInterval: 1.0, target: self, selector: #selector(UIMenuController.update), userInfo: nil, repeats: true)

El cambio de nombre ocurrió en Swift 3 y otras respuestas ya han hecho la actualización ...
— Eric Aya
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.