web-dev-qa-db-fra.com

Comment utiliser Timer (anciennement NSTimer) dans Swift?

J'ai essayé

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

Mais, j'ai une erreur en disant

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

Cela fonctionnera:

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
}

Pour Swift 4, la méthode dont vous voulez obtenir le sélecteur doit être exposée à Objective-C, ainsi l'attribut @objc doit être ajouté à la déclaration de méthode.

514
Oscar Swanros

Événement répété

Vous pouvez utiliser un minuteur pour effectuer une action plusieurs fois, comme illustré dans l'exemple suivant. Le minuteur appelle une méthode pour mettre à jour une étiquette toutes les demi-secondes.

enter image description here

Voici le code pour cela:

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)"
    }
}

Événement retardé

Vous pouvez également utiliser une minuterie pour planifier un événement ponctuel dans le futur. La principale différence avec l'exemple ci-dessus est que vous utilisez repeats: false au lieu de true.

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

L'exemple ci-dessus appelle une méthode nommée delayedAction deux secondes après le réglage de la minuterie. Il ne se répète pas, mais vous pouvez toujours appeler timer.invalidate() si vous devez annuler l'événement avant qu'il ne se produise.

Remarques

  • S'il existe un risque de démarrer votre instance de minuteur plusieurs fois, assurez-vous d'invalider d'abord l'instance de minuteur ancienne. Sinon, vous perdez la référence à la minuterie et vous ne pouvez plus l'arrêter. (voir ce Q & A )
  • N'utilisez pas de minuteries quand elles ne sont pas nécessaires. Voir la section sur les minuteries du Guide d'efficacité énergétique pour les applications iOS .

Apparenté, relié, connexe

141
Suragch

Mis à jour à Swift 4, utilisant 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)
    }

}
29
igraczech

Depuis iOS 10, il existe également une nouvelle méthode de fabrique de minuterie basée sur des blocs qui est plus propre que d'utiliser le sélecteur:

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

Swift 3, pré 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)
      }
    }

Remarques

  • Il doit être dans la file d'attente principale
  • La fonction de rappel peut être publique, privée, ...
  • La fonction de rappel doit être @objc
20
onmyway133

Vérifier avec:

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)
15
Midhun MP

Vous devrez utiliser Minuteur au lieu de NSTimer dans Swift 3.

Voici un exemple:

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
Ondrej Kvasnovsky

for Swift 3 et Xcode 8.2 (C'est bien d'avoir des blocs, mais si vous compilez pour iOS9 ET voulez userInfo):

...

        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
ingconti

SimpleTimer (Swift 3.1)

Pourquoi?

Il s'agit d'une classe de minuterie simple dans Swift qui vous permet de:

  • Minuterie locale portée
  • Chainable
  • Une doublure
  • Utiliser des rappels réguliers

Usage:

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

Code:

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()
    }
}
5
eonist

Dans Swift quelque chose comme ceci avec @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()
}
2
Nik Kov
timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(createEnemy), userInfo: nil, repeats: true)

Et créer de l'amusement par le nom createEnemy

fund createEnemy ()
{
do anything ////
}
2
Khaled Hamdy

Si vous initiez la méthode du timer

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

func update(_ timer : Timer) {

}

puis ajoutez-le à la boucle en utilisant la méthode autre sélecteur ne sera pas appelé

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

NOTE: Si vous voulez que cela répète, make répète vrai et conserve la référence du temporisateur, sinon la méthode update ne sera pas appelée.

Si vous utilisez cette méthode.

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

conservez une référence pour une utilisation ultérieure si répétitions est vraie.

1
Surjeet Rajput