Обновление UILabel, когда таймер отсчитывает каждую секунду в Swift 4.2

Новенький тут учу себя Swift. Создал свое первое личное приложение и уперся в стену после нескольких поисков здесь, на YouTube и в Google. Это мой первый раз, когда я публикую вопрос (поскольку я смог найти другие ответы здесь).

У меня проблемы с обновлением таймера на UILabel. Мне удалось найти код в более старых версиях Swift, который запускает таймер и ведет обратный отсчет. Затем я понял, как разбить секунды на минуты и секунды.

Но я обнаружил, что когда я запускаю приложение, таймер показывает "30:0" (другая проблема, которую мне нужно выяснить) и никогда не ведет обратный отсчет. Когда я покидаю страницу в симуляторе и возвращаюсь, только тогда UILabel обновляется.

Я знаю, что viewdidload загружается только в первый момент открытия страницы. Мне трудно понять, как заставить UILabel обновляться каждый раз, когда изменяется секунда. Я не уверен, какой код реализовать.

Большое спасибо!

import UIKit

var timer = Timer()
var timerDuration: Int = 1800

// This converts my timeDuration from seconds to minutes and seconds.
func secondsToHoursMinutesSeconds (seconds : Int) -> (h: Int, m : Int, s : Int) {
    return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)
}

class lyricWriteViewController: UIViewController {
    //This takes the function to convert minutes and seconds and accepts an input, which I've chosen the variable timeDuration (which is currently 1800 seconds.
    var theTimer = (h: 0, m: 0, s: 0)

    @IBOutlet weak var countdownTimer: UILabel!
    @IBOutlet weak var randomLyric: UILabel!
    @IBOutlet weak var titleInput: UITextField!
    @IBOutlet weak var lyricInput: UITextView!

    override func viewDidLoad() {
        super.viewDidLoad()

        //This line takes a random array number and shows it on the textlabel.

        randomLyric.text = oneLiner
        theTimer = secondsToHoursMinutesSeconds(seconds: timerDuration)

        //This is the code the does the counting down
        timer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(lyricWriteViewController.counter), userInfo: nil, repeats: true)
    }

    @objc func counter() {
        timerDuration -= 1

        // Below is the timer view I've created. It has converted seconds to minutes and seconds but the screen won't refresh. Also, when the seconds number hits zero, it does "0" instead of "00".
        let displayTimer = "\(theTimer.m) : \(theTimer.s)"
        countdownTimer.text = String(displayTimer)

        //When the timer hits 0, it stops working so that it doesn't go into negative numbers

        if timerDuration == 0 {
            timer.invalidate()
        }
    }

    func submitlyricsButton(_ sender: UIButton) {
        //I will eventually tie this to a completed lyric tableview.
    }
}

person codeDerek    schedule 26.10.2018    source источник
comment
Чтобы убедиться, что ваш таймер работает нормально, не могли бы вы создать журнал и распечатать значение displayTimer непосредственно перед выполнением countdownTimer.text = String(displayTimer)   -  person iOSer    schedule 26.10.2018
comment
Таймер работает, однако единственная проблема, с которой я сталкиваюсь, это отображение 0 перед 0-9. Например: 29:10, 29:9, 29:8. вместо 29:09, 29:08... и т.д.   -  person codeDerek    schedule 28.10.2018


Ответы (2)


Это потому, что вы не обновляете значение theTimer. Поскольку viewDidLoad() вызывается, когда он не работает нормально, вам необходимо обновить значение theTimer после вычитания из него 1. Итак, переместите эту строку:

theTimer = secondsToHoursMinutesSeconds(seconds: timerDuration)

в функции counter() после timerDuration -= 1. Итак, ваша функция должна выглядеть так:

@objc func counter() {
    timerDuration -= 1
    if timerDuration == 0 {
        timer.invalidate()
    } else {
        theTimer = secondsToHoursMinutesSeconds(seconds: timerDuration)
        let displayTimer = "\(theTimer.m) : \(theTimer.s)"
        countdownTimer.text = String(displayTimer)
    }        
}

Также переместите все это внутрь контроллера:

var timer = Timer()
var timerDuration: Int = 1800

// This converts my timeDuration from seconds to minutes and seconds.
func secondsToHoursMinutesSeconds (seconds : Int) -> (h: Int, m : Int, s : Int){
return (seconds / 3600, (seconds % 3600) / 60, (seconds % 3600) % 60)}

Поскольку timerDuration является глобальным, вам придется закрыть приложение и запустить его снова, чтобы снова увидеть, как таймер работает.

person Sharad Chauhan    schedule 26.10.2018
comment
Удивительно! Спасибо ОООООООООчень большое. Это было хорошим уроком для меня. Это была простая настройка, но без вас я бы не разобрался. Благодарю вас! - person codeDerek; 26.10.2018

Замените countdownTimer.text = String(displayTimer) на

DispatchQueue.main.async {
    countdownTimer.text = String(displayTimer)
}

Я думаю, что здесь происходит то, что, поскольку countdownTimer.text = String(displayTimer) не работает в основном потоке, он не обновляется немедленно. Однако это происходит через некоторое время (как вы сказали, когда вы перемещаетесь по экрану).

person iOSer    schedule 26.10.2018