问题描述
我正在尝试创建一个测验应用程序,该应用程序在计时器到期时(即10秒,并且我希望Timer的间隔为1秒)为每个问题提供一个计时器,它会自行重置并提取下一个问题,然后再次计时器从10重新开始...但是我的问题是,当第一个问题被加载时,计时器没有遵循固定的时间间隔,它显示的间隔为2 ...即10,8,6 ..然后对于第二个问题,它使跳转为3秒间隔,并且间隔类似地增加。
导入UIKit
class ViewController: UIViewController {
let allQuestions = QuestionsBundle()
var pickedAnswer : Int = 0
var questionCounter = 0
var score : Int = 0
var timer: Timer!
@IBOutlet weak var questionLabel: UILabel!
@IBOutlet weak var countDownLabel: UILabel!
@IBOutlet weak var ansLbl1: UILabel!
@IBOutlet weak var ansLbl2: UILabel!
@IBOutlet weak var ansLbl3: UILabel!
@IBOutlet weak var ansLbl4: UILabel!
@IBOutlet weak var checkBox1: CheckBox!
@IBOutlet weak var checkBox2: CheckBox!
@IBOutlet weak var checkBox3: CheckBox!
@IBOutlet weak var checkBox4: CheckBox!
var checkBoxlist : [CheckBox] = []
@IBAction func correct_Answer_ChecBox_Btn(_ sender: AnyObject) {
//print("\(sender.tag) <==> \(String(describing: question?.correctAnswer))")
updateCheckBoxes(sender: sender)
if sender.tag == question?.correctAnswer{
question?.isAnswerCorrect = true
question?.selectedAnswer = sender.tag
//score = score + 1
}
else {
question?.isAnswerCorrect = false
}
}
func updateCheckBoxes(sender: AnyObject){
for checkBoxItem in checkBoxlist{
if checkBoxItem.tag != sender.tag {
checkBoxItem.isChecked = false
}
}
}
@IBOutlet weak var nextButton: UIButton!
@IBAction func nextBtnClicked(_ sender: AnyObject) {
do{
try handleNextQuestion()
}
catch{
movetoResultView()
}
}
func handleNextQuestion() throws {
nextQuestion()
if questionCounter == allQuestions.list.count-1{
finishButton.isHidden = false
nextButton.isHidden = true
//scoreLbl.text = "\(score)"
}
}
var question : Question?
var countTime = 10.0
override func viewDidLoad() {
super.viewDidLoad()
finishButton?.isHidden = true
checkBoxlist = fetchCheckBoxList()
question = fetchQuestion()
setQuizView(question: question!)
// Do any additional setup after loading the view,typically from a nib.
}
// set all questions in a function
@objc func update() {
if(countTime > 0) {
countTime = countTime - 1
self.countDownLabel.text = String(countTime)
}else{
timer.invalidate()
countTime = 10.0
do{
try handleNextQuestion()
}
catch{
movetoResultView()
}
}
}
func startTimer() {
timer = Timer.scheduledTimer(timeInterval: 1.0,target: self,selector: #selector(ViewController.update),userInfo: nil,repeats: true)
}
func setQuizView(question:Question) {
self.countDownLabel.text = "10"
startTimer()
questionLabel.text = question.questionText
ansLbl1.text = question.answer1
ansLbl2.text = question.answer2
ansLbl3.text = question.answer3
ansLbl4.text = question.answer4
if question.selectedAnswer == Constants.DEFAULT_ANSWER {
for checkBoxItem in checkBoxlist{
checkBoxItem.isChecked = false
}
}
}
@IBOutlet weak var finishButton: UIButton!
// prepare segue
override func prepare(for segue: UIStoryboardSegue,sender: Any?) {
if segue.identifier == resultScreenIdentifier{
let vc = segue.destination as! ResultViewController
vc.data = sender as! String
}
}
let resultScreenIdentifier = "resultScreenSegue"
func movetoResultView(){
performSegue(withIdentifier: resultScreenIdentifier,sender: score)
}
@IBAction func finishButtonClicked(_ sender: UIButton) {
//perform segue
let score = "\(calculatescore())"
movetoResultView()
}
// calculate the score of quiz using loop
func calculatescore()->Int{
var numOfCorrectAnswers = 0
for question in allQuestions.list{
if question.isAnswerCorrect {
numOfCorrectAnswers = numOfCorrectAnswers + 1
//print(numOfCorrectAnswers)
}
}
return numOfCorrectAnswers
}
func nextQuestion(){
showResultView(isCorrect: (question?.isAnswerCorrect)!)
questionCounter = questionCounter + 1
question = fetchQuestion()
setQuizView(question: question!)
}
func fetchQuestion() -> Question{
return allQuestions.list[questionCounter]
}
func fetchCheckBoxList() -> [CheckBox]{
let arr : [CheckBox] = [checkBox1,checkBox2,checkBox3,checkBox4]
return arr
}
}
解决方法
Timer
并不是特别准确。他们会遭受明显的抖动。
一种更好的方法是创建一个表示到期时间的Date
(即Date(timeIntervalSinceNow:10)
,然后以更短的间隔运行Timer
(我建议大约0.1秒)。然后,您可以根据目标Date
计算剩余时间,并检查目标日期是否过去。