¿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.