I am creating a trivia app in swift and I have a timer that counts down each question. However as the user progresses with each question the timer speeds up. Can someone help me fix this?
My runGameTimer function:
func runGameTimer()
{
gameTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(RockTriviaViewController.updateGameTimer), userInfo: nil, repeats: true)
}
My updateGameTimer function:
@objc func updateGameTimer()
{
gameInt -= 1
timerLabel.text = String(gameInt)
if (gameInt == 0)
{
gameTimer.invalidate()
/*
if (currentQuestion != rockQuestions[questionSet].count)
{
newQuestion()
}
else
{
performSegue(withIdentifier: "showRockScore", sender: self)
}
*/
}
}
Where I call my code:
func newQuestion()
{
gameInt = 11
runGameTimer()
rockQuestion.text = rockQuestions[questionSet][currentQuestion]
rightAnswerPlacement = arc4random_uniform(3)+1
var Button: UIButton = UIButton()
var x = 1
for i in 1...3
{
Button = view.viewWithTag(i) as! UIButton
if(i == Int(rightAnswerPlacement))
{
Button.setTitle(rockAnswers[questionSet][currentQuestion][0], for: .normal)
}
else
{
Button.setTitle(rockAnswers[questionSet][currentQuestion][x], for: .normal)
x = 2
}
}
currentQuestion += 1
}
You're calling runGameTimer()
in every call to newQuestion()
. If a timer was already running then you'll add a new timer each time, and they will all call your selector. So if you have 3 timers running, your selector will be called 3x as often. That's not what you want.
Change your timer variable to be weak
:
weak var gameTimer: Timer?
And then in runGameTimer invalidate the timer before creating a new one, using optional chaining:
func runGameTimer() {
gameTimer?.invalidate() //This will do nothing if gameTimer is nil.
//it will also cause the gameTimer to be nil since it's weak.
gameTimer = Timer.scheduledTimer(timeInterval: 1, target: self, selector: #selector(RockTriviaViewController.updateGameTimer), userInfo: nil, repeats: true)
}
By making the game timer weak it will get set to nil as soon as it's invalidated. (When you schedule a timer the system retains it while it is running so it stays valid as long as it continues to run.)
By using optional chaining to reference the timer:
gameTimer?.invalidate()
The code doesn't do anything if gameTimer is nil.