1
votes

Swift | La minuterie ne s'arrêtera pas lors de l'invalidation de l'appel, accélère plutôt

J'ai créé un chronomètre à l'aide de la minuterie dans cette application et j'ai ajouté un bouton de démarrage et d'arrêt pour mettre en pause et lire la même chose. Lorsque le bouton-poussoir est enfoncé, il est envoyé à une fonction qui invalide la minuterie et il doit s'arrêter. Mais étrangement assez lorsque vous appuyez sur le bouton d'arrêt, au lieu d'arrêter la minuterie accélère d'une manière ou d'une autre Je n'ai pas changé l'intervalle de temps sauf une fois juste en le déclarant.

J'ai essayé de désactiver le bouton de démarrage une fois qu'il est enfoncé et même de le cacher. a également essayé de changer l'intervalle de temps mais rien ne fonctionne. plus j'appuie sur le bouton start stop, plus il accélère et commence à aller beaucoup plus vite que l'intervalle de temps mentionné.

startButton.frame = CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1)
    startButton.setTitle("Start Timer", for: .normal)
    self.view.addSubview(startButton)
    startButton.setTitleColor(.white , for: .normal)
    startButton.backgroundColor = .red
    startButton.addTarget(self, action: #selector(playButton(_:)), for: .allTouchEvents)

    stopButton.frame = CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1)
    stopButton.setTitle("Stop Timer", for: .normal)
    stopButton.setTitleColor(.white , for: .normal)
    stopButton.backgroundColor = .red
    stopButton.addTarget(self, action: #selector(pauseButton(_:)), for: .allTouchEvents)
@objc func playButton(_ sender : Any)
{
    timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)
    startButton.isEnabled = false
    stopButton.isEnabled = true
    isRunning = true
    self.view.addSubview(stopButton)
    startButton.isHidden = true
    stopButton.isHidden = false



}

@objc func pauseButton(_ sender: Any) {
    self.view.addSubview(startButton)
    timer.invalidate()

    stopButton.isHidden = true
    startButton.isHidden = false

    startButton.isEnabled = true
    stopButton.isEnabled = false

    isRunning = false

}


@objc func updateTimer(_ sender : Any)
{
    counter += 0.1
    titleLabel.text = String(format: "%.1f", counter)
}


0 commentaires

3 Réponses :


1
votes

Essayez d'ajouter les deux boutons en même temps en masquant le bouton d'arrêt et masquez et affichez simplement les boutons en cliquant sur le bouton. Votre méthode de bouton de lecture s'exécute à chaque fois, lorsque vous essayez d'arrêter le minuteur


5 commentaires

J'ai ajouté un bouton d'arrêt dans ses propriétés comme le bouton de démarrage et supprimé toutes les lignes de code de masquage du bouton de démarrage, mais rien n'a changé. Cela n'explique pas non plus pourquoi la minuterie s'accélérerait et commencerait à aller de plus en plus vite à chaque clic d'arrêt


Cela est dû au fait que votre méthode playButton est appelée encore et encore. vérifiez-le en plaçant un point d'arrêt sur cette fonction


ok merci beaucoup cela a fonctionné et j'ai passé des heures mais je n'ai pas pu voir l'erreur


Je les ai utilisés mais je n'ai pas remarqué qu'ils étaient arrêtés deux fois, cela semblait être un décalage dans mon PC, mais je ne sais toujours pas pourquoi cela accélérerait même s'il était appelé encore et encore puisque la définition initiale de l'intervalle ne change jamais


C'est parce que chaque fois que la méthode du bouton de lecture est appelée, un nouveau minuteur séparé est planifié, ce qui provoque l'appel de la méthode updateTimer séparément. Ainsi, chaque fois que cela se produit, la valeur du compteur augmente



1
votes

Autant que je sache, vous avez 2 erreurs.

Le premier est mentionné par l'autre réponse. Il est vrai que vous ne devriez pas toujours ajouter un nouvel UIButton et utiliser simplement la propriété hide / unhide pour chaque bouton.

La deuxième erreur concerne la façon dont vous ajoutez une cible. Vous utilisez .allTouchEvents, mais vous pourriez avoir l'intention d'utiliser .touchUpInside comme état de contrôle.

Veuillez consulter le code corrigé ci-dessous pour votre référence:

import UIKit

class ViewController: UIViewController {

@IBOutlet weak var titleLabel: UILabel!

var startButton: UIButton!
var stopButton: UIButton!
var timer: Timer!
var counter: Double = 0.0

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    startButton = UIButton(frame: CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1))
    startButton.setTitle("Start Timer", for: .normal)
    startButton.setTitleColor(.white , for: .normal)
    startButton.backgroundColor = .red
    startButton.addTarget(self, action: #selector(playButton(_:)), for: .touchUpInside)
    self.view.addSubview(startButton)
    self.startButton.isHidden = false

    stopButton = UIButton(frame: CGRect(x: 0, y: UIScreen.main.bounds.height * 0.9 , width: UIScreen.main.bounds.width, height: UIScreen.main.bounds.height * 0.1))
    stopButton.setTitle("Stop Timer", for: .normal)
    stopButton.setTitleColor(.white , for: .normal)
    stopButton.backgroundColor = .red
    stopButton.addTarget(self, action: #selector(pauseButton(_:)), for: .touchUpInside)
    self.view.addSubview(stopButton)
    self.stopButton.isHidden = true
}

@objc func playButton(_ sender : Any) {
    timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)

    startButton.isEnabled = false
    stopButton.isEnabled = true
    startButton.isHidden = true
    stopButton.isHidden = false
}

@objc func pauseButton(_ sender: Any) {
    timer.invalidate()

    stopButton.isHidden = true
    startButton.isHidden = false
    startButton.isEnabled = true
    stopButton.isEnabled = false
}


@objc func updateTimer(_ sender : Any)
{
    counter += 0.1
    titleLabel.text = String(format: "%.1f", counter)
}
}

p>


1 commentaires

merci pour une réponse aussi détaillée et précise, j'aurais aimé pouvoir remarquer au lieu de perdre des heures, apprécier l'effort



1
votes

Vous avez déjà 2 bonnes réponses, mais je vais ajouter mon 2p car je pense que les prémisses sur lesquelles vous avez commencé ne sont pas correctes.

Votre plus grande erreur est d'avoir 2 boutons en premier lieu. Vous n'auriez pas eu le problème si vous n'aviez qu'un seul bouton et que vous l'aviez stylé au besoin.

class MyTest {
    let magicButton = UIButton()
    let timer: Timer?

    override viewDidLoad() {
        super.viewDidLoad()

        // Setup Button
        magicButton.addTarget(self, action: #selector(buttonPress(_:)), for: .allTouchEvents)
        magicButton.setTitleColor(.white , for: .normal)
        magicButton.frame = yourFrame
        view.addSubview(magicButton)

        customiseButton()
    }

    @objc private func buttonPress() {
        if timer == nil {
            timer = Timer.scheduledTimer(timeInterval: 1, target: self , selector: #selector(updateTimer), userInfo: nil, repeats: true)
        } else {
            timer.invalidate()
        }

        customiseButton()
    }

    private func customiseButton() {
        let isStartButton = timer == nil
        let buttonTitle = isStartButton ? "Start" : "Stop"
        let buttonBackgroundColor: UIColor = isStartButton ? .green : .red

        magicButton.setTitle(buttonTitle, for: .normal)
        magicButton.backgroundColor = buttonBackgroundColor
    }
}

// add updateTimer function too

De cette façon, vous avez moins de code à maintenir et aucun conflit entre les éléments cachés montré, donc moins de choses qui pourraient mal tourner. La magie se produit dans la méthode buttonPress où si un minuteur est démarré, vous l'arrêtez, sinon vous en démarrez un, suivi d'une mise à jour rapide de l'interface utilisateur du bouton.


0 commentaires