Swift NSTiimer 不遵循指定的间隔 [英] Swift NSTiimer not following specified Interval
问题描述
我正在尝试创建一个测验应用程序,该应用程序在计时器到期时(即 10 秒,我希望计时器的间隔为 1 秒)为每个问题提供一个计时器,它会自行重置并获取下一个问题并再次使用计时器从 10 点重新开始...但我的问题是,当加载第一个问题时,计时器不遵循固定间隔,它显示间隔为 2 ... 即 10,8,6 .. 然后对于第二个问题,它跳为 3secs 间隔,同样间隔增加.
I am trying to create a quiz app which has a timer for each question when the timer expires (i.e. 10 seconds and I want Timer to have an interval of 1 sec) it resets it self and next question is fetched and Timer again restart from 10... But my issue is the timer doesn't follow a fixed interval when first question is loaded it shows interval of 2 ... i.e. 10,8,6 .. and then for second question it makes jump for 3 secs interval and similarly the interval increases.
导入 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
不是特别准确.它们可能会受到严重抖动的影响.
Timer
s are not particularly accurate. They can suffer from significant jitter.
更好的方法是创建一个表示过期时间的Date
(即Date(timeIntervalSinceNow:10)
,然后运行一个Timer
间隔更短(我建议大约 0.1 秒).然后您可以根据目标 Date
计算剩余时间,并检查目标日期是否在过去.
A better approach is to create a Date
that represents the expiration time (ie Date(timeIntervalSinceNow:10)
and then run a Timer
with a much shorter interval (I would suggest around 0.1 second). You can then calculate the time remaining based on the target Date
and check if the target date is in the past.
这篇关于Swift NSTiimer 不遵循指定的间隔的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!