1

I'm developing a quiz app for educational use and whilst testing to see if it was 'foolproof' noticed that a second tap would transfer to the next question causing my quiz to jump 2 questions.

In the quiz, I have a pop-up that either tells the student they were correct or tells them what the correct answer was. I delay the loading of the next question for about 4 seconds to let student have another quick look at question and possible answers.

I've tried using isUserInteractionEnabled = false to prevent a second tap being detected but it doesn't seem to be having any effect. Code for this section is:

@IBAction func answerPressed(_ sender: UIButton) {

    if sender.tag == selectedAnswer {
        self.view.isUserInteractionEnabled = false
        ProgressHUD.showSuccess("Correct")
        print("correct")
        score = score + 1
        scoreLabel.text = "Score: \(score)"

        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
            // Put your code which should be executed with a delay here

            self.progressClick = self.progressClick + 1
            self.questionNumber = self.questionNumber + 1

            self.updateProgress()
            self.updateQuestion()
        })
        self.view.isUserInteractionEnabled = true
    }

    else {
        self.view.isUserInteractionEnabled = false
        ProgressHUD.showError("Good Try. \(allQuestions.list[questionNumber].revealAnswer)")
        print("wrong")


        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(4), execute: {
        // Put your code which should be executed with a delay here

            self.progressClick = self.progressClick + 1
            self.questionNumber = self.questionNumber + 1

            self.updateProgress()
            self.updateQuestion()
        })

        self.view.isUserInteractionEnabled = true
    }
} 

func updateQuestion(){

    if questionNumber < (presentNumber + 10) {
        questionDiagram.image = UIImage(named:(allQuestions.list[questionNumber].questionPicture))
        questionText.text = "Q \(questionNumber + 1). " + allQuestions.list[questionNumber].question
        optionA.setTitle(allQuestions.list[questionNumber].optionA, for: UIControl.State.normal)
        optionB.setTitle(allQuestions.list[questionNumber].optionB, for: UIControl.State.normal)
        optionC.setTitle(allQuestions.list[questionNumber].optionC, for: UIControl.State.normal)
        optionD.setTitle(allQuestions.list[questionNumber].optionD, for: UIControl.State.normal)
        selectedAnswer = allQuestions.list[questionNumber].correctAnswer
    }

    else if questionNumber == allQuestions.list.count {
        let alert = UIAlertController(title: "Awesome", message: "Finished all the Quizes. Do you want to start again?", preferredStyle: .alert)   
        let restartAction = UIAlertAction(title: "Restart", style: .default, handler: {action in self.restartQuiz()})
        alert.addAction(restartAction)
        present(alert, animated: true, completion: nil)  
    }

    else if questionNumber == 10 {
        let alert = UIAlertController(title: "Well Done", message: "That Quiz is done. The next Quiz will now load.", preferredStyle: .alert)
        let restartAction2 = UIAlertAction(title: "Continue", style: .default, handler: {action in self.restartQuiz()})
        alert.addAction(restartAction2)
        present(alert, animated: true, completion: nil)   
    }  
}
Bhaumik
  • 1,218
  • 1
  • 11
  • 20
  • You're disabling userInteraction start some delayed stuff and enable userInteraction immediately. So in fact it is never really disabled (ok for some microseconds). Maybe you should enable userinteraction at the end of your dispatched code? – Tom Mar 07 '19 at 23:05
  • Possible duplicate of [Disable swipe back gesture in Swift](https://stackoverflow.com/questions/31731751/disable-swipe-back-gesture-in-swift) – El Tomato Mar 07 '19 at 23:08

4 Answers4

0

Reenabling user interactions is part of what needs to be delayed. Change

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
        // Put your code which should be executed with a delay here

        self.progressClick = self.progressClick + 1
        self.questionNumber = self.questionNumber + 1

        self.updateProgress()
        self.updateQuestion()
    })
    self.view.isUserInteractionEnabled = true

To

   DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
        // Put your code which should be executed with a delay here

        self.progressClick = self.progressClick + 1
        self.questionNumber = self.questionNumber + 1

        self.updateProgress()
        self.updateQuestion()
        self.view.isUserInteractionEnabled = true
    })

And so on, throughout.

matt
  • 515,959
  • 87
  • 875
  • 1,141
0

you can do this:

UIApplication.shared.beginIgnoringInteractionEvents() 

and after propagating to next quiz

UIApplication.shared.endIgnoringInteractionEvents()
AppleCiderGuy
  • 1,249
  • 1
  • 9
  • 16
0

A fix with the storyboard would be do overlay everything with a clear UIView: name that, for example, Display, then, run the following functions when needed.

func disallowTouch() {
    self.DisplayView.isHidden = false
    self.DisplayView.isUserInteractionEnabled = false
{

You'll of course have to create another function doing the opposite:

func allowTouch() {
    self.DisplayView.isHidden = true
    self.DisplayView.isUserInteractionEnabled = true
    {

I hope this helps, as it's not a conventional fix.

0

Problem:

It is because you are enabling user interaction right away.

Solution:

You need to move self.view.isUserInteractionEnabled = true for all your conditions inside DispatchQueue method in order to wait before enabling it again.

Check this sample:

if sender.tag == selectedAnswer {
    self.view.isUserInteractionEnabled = false
    ProgressHUD.showSuccess("Correct")
    print("correct")
    score = score + 1
    scoreLabel.text = "Score: \(score)"

    DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
        // Put your code which should be executed with a delay here

        self.progressClick = self.progressClick + 1
        self.questionNumber = self.questionNumber + 1

        self.updateProgress()
        self.updateQuestion()
        self.view.isUserInteractionEnabled = true //This line moved inside DispatchQueue
    })

}
Bhaumik
  • 1,218
  • 1
  • 11
  • 20