web-dev-qa-db-fra.com

Timer.scheduledTimer ne fonctionne pas dans Swift 3

Je souhaite appeler la méthode func adjustmentBestSongBpmHeartRate() toutes les 1,1 seconde. J'ai utilisé Timer, mais ça ne marche pas. J'ai lu le document et trouvé beaucoup d'exemples de code, cela fonctionne toujours! Y a-t-il quelque chose qui m'a manqué?

 timer = Timer.scheduledTimer(timeInterval: 1.1, target: self, selector: #selector(self.adjustmentBestSongBpmHeartRate), userInfo: nil, repeats: false)
 timer.fire()

 func adjustmentBestSongBpmHeartRate() {
    print("frr")
 }
12
Jing Bian

Les méthodes de minuterie avec un sélecteur sont supposées avoir un paramètre: la minuterie elle-même. Ainsi, votre code devrait ressembler à ceci: 1

Timer.scheduledTimer(timeInterval: 1.1, 
    target: self, 
    selector: #selector(self.adjustmentBestSongBpmHeartRate(_:), 
    userInfo: nil, 
    repeats: false)

@objc func adjustmentBestSongBpmHeartRate(_ timer: Timer) {
    print("frr")
 }

Notez que si votre application ne s'exécute que sur iOS> = 10, vous pouvez utiliser la nouvelle méthode qui prend un bloc à appeler plutôt qu'une cible/sélecteur. Beaucoup plus propre et plus sûr du type:

class func scheduledTimer(withTimeInterval interval: TimeInterval, 
    repeats: Bool, 
    block: @escaping (Timer) -> Void) -> Timer

Ce code ressemblerait à ceci:

 timer = Timer.scheduledTimer(withTimeInterval: 1.1, 
        repeats: false) {
    timer in
    //Put the code that be called by the timer here.
    print("frr")
    }

Notez que si votre bloc/fermeture du temporisateur nécessite l’accès aux variables d’instance de votre classe, vous devez faire particulièrement attention à self. Voici un bon modèle pour ce type de code:

 timer = Timer.scheduledTimer(withTimeInterval: 1.1, 
        repeats: false) {

    //"[weak self]" creates a "capture group" for timer
    [weak self] timer in

    //Add a guard statement to bail out of the timer code 
    //if the object has been freed.
    guard let strongSelf = self else {
        return
    }
    //Put the code that be called by the timer here.
    print(strongSelf.someProperty)
    strongSelf.someOtherProperty = someValue
    }

Modifier:

1: Je devrais ajouter que la méthode que vous utilisez dans le sélecteur doit utiliser la répartition dynamique Objective-C. Vous pouvez déclarer la méthode avec le qualificatif @objc, vous pouvez déclarer la classe entière qui définit le sélecteur avec le qualificatif @objc ou définir la classe qui définit le sélecteur comme une sous-classe de NSObject ou toute classe héritant de NSOBject. (Il est assez courant de définir la méthode que la minuterie appelle à l’intérieur de UIViewController, qui est une sous-classe de NSObject, de sorte que cela "fonctionne".

MODIFIER

Dans Swift 4, les méthodes qui doivent être appelées à partir d'Objective-C doivent désormais être étiquetées individuellement avec le qualificatif @objc. Le commentaire "ça fonctionne" n'est plus vrai.

20
Duncan C

J'ai constaté que la création du minuteur dans une opération OperationQueue ne fonctionnait pas. Je suppose que c'est parce qu'il n'y a pas de runloop.

Par conséquent, le code suivant a résolu mon problème:

   DispatchQueue.main.async {
            // timer needs a runloop?
            self.timeoutTimer = Timer.scheduledTimer(timeInterval: self.timeout, target: self, selector: #selector(self.onTimeout(_:)), userInfo: nil, repeats: false)
}
11
Nick H247

Swift 3

Dans mon cas, cela a fonctionné après que j'ai ajouté à ma méthode le préfixe @obj

Class TestClass {
   private var timer: Timer?

   func start() {
        guard timer == nil else { return }
        timer = Timer.scheduledTimer(timeInterval: 60, target: self, selector: #selector(handleMyFunction), userInfo: nil, repeats: false)
    }

    func stop() {
        guard timer != nil else { return }
        timer?.invalidate()
        timer = nil
    }


    @objc func handleMyFunction() {
        // Code here
    }
}
10
Jorge Casariego

Essaye ça - 

if #available(iOS 10.0, *) {
     self.timer = Timer.scheduledTimer(withTimeInterval: 0.2, repeats: false, block: { _ in
         self.update()
     })
} else {
     self.timer = Timer.scheduledTimer(timeInterval: 0.2, target: self, selector: #selector(self.update), userInfo: nil, repeats: false)
}

Généralement, le problème devait provenir de la version iOS du mobile.

4
Nikhil Manapure

J'ai résolu la question que je me suis posée… .. J'utilise Apple Watch pour contrôler mon application iPhone. J'essaie d'appuyer sur un bouton sur Apple Watch pour présenter un nouveau contrôleur de vue sur iphone.

Lorsque j'écris Timer dans override func viewDidLoad(), Timer ne fonctionne pas. Je déplace la minuterie sur override func viewWillAppear() cela fonctionne.

Je pense qu'il y a peut-être quelque chose qui cloche dans le contrôle par Apple Watch


2
Jing Bian

mes deux cents . J'ai lu à propos de "didLoad" et en l'invoquant . afin que nous puissions utiliser un délai:

class ViewController: UIViewController {

    var timer: Timer?

    override func viewDidLoad() {
        super.viewDidLoad()
        startTimer()
    }


    final func killTimer(){
        self.timer?.invalidate()
        self.timer = nil
    }


    final private func startTimer() {

        // make it re-entrant:
        // if timer is running, kill it and start from scratch
        self.killTimer()
        let fire = Date().addingTimeInterval(1)
        let deltaT : TimeInterval = 1.0

        self.timer = Timer(fire: fire, interval: deltaT, repeats: true, block: { (t: Timer) in

            print("hello")

        })

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

    }
0
ingconti