1

Im developing a quiz app and on the first UIViewController the user is asked a question and given four buttons to press as answers. If they get the answer correct, that element is removed from the array of questions to be asked. However if I implement a segue to another view controller that asks the user if they want to continue when it segues back to the first view controller to ask another question the array is refilled with questions the user has already answered even though they are supposed to be removed. How can I make sure once I segue to the and from the second viewcontroller that asks the user if they want to continue that the array of questions doesn't refill with already answered questions?

Here is my code:

import UIKit

class ViewController: UIViewController {

var questionList = [String]()

func updateCounter() {

    counter -= 1
    questionTimer.text = String(counter)

    if counter == 0 {
        timer.invalidate()
        wrongSeg()
        counter = 15
    }
}


func randomQuestion() {

    //random question
    if questionList.isEmpty {
        questionList = Array(QADictionary.keys)
        questionTimer.text = String(counter)

    }

    let rand = Int(arc4random_uniform(UInt32(questionList.count)))
    questionLabel.text = questionList[rand]

    //matching answer values to go with question keys
    var choices = QADictionary[questionList[rand]]!

    questionList.remove(at: rand)


    //create button
    var button:UIButton = UIButton()

    //variables
    var x = 1
    rightAnswerBox = arc4random_uniform(4)+1

        for index in 1...4 {

            button = view.viewWithTag(index) as! UIButton
            if (index == Int(rightAnswerBox)){
                button.setTitle(choices[0], for: .normal)
            }
            else {
                button.setTitle(choices[x], for: .normal)
                x += 1
            }

            randomImage()
        }
    }


let QADictionary = ["Who is Thor's brother?" : ["Atum", "Loki", "Red Norvell", "Kevin Masterson"], "What is the name of Thor's hammer?" : ["Mjolinr", "Uru", "Stormbreaker", "Thundara"], "Who is the father of Thor?" : ["Odin", "Sif", "Heimdall", "Balder"]]

//wrong view segue
func wrongSeg() {
   performSegue(withIdentifier: "incorrectSeg", sender: self)
}

//proceed screen
func rightSeg() {
    performSegue(withIdentifier: "correctSeg", sender: self)
}
        //variables
var rightAnswerBox:UInt32 = 0
var index = 0

//Question Label
@IBOutlet weak var questionLabel: UILabel!

//Answer Button
@IBAction func buttonAction(_ sender: AnyObject) {

if (sender.tag == Int(rightAnswerBox) {
    //rightSeg()
    print ("Correct!")
}
    if counter != 0 {
        counter = 15
        questionTimer.text = String(counter)
    }
else if (sender.tag != Int(rightAnswerBox)) {
    wrongSeg()
print ("Wrong!")
    timer.invalidate()
    questionList = []

    }
   randomQuestion()
}

override func viewDidAppear(_ animated: Bool) {
randomQuestion()
}

//variables
var counter = 15
var timer = Timer()
@IBOutlet weak var questionTimer: UILabel!

override func viewDidLoad() {
    super.viewDidLoad()
    // Do any additional setup after loading the view, typically from a nib.

    timer = Timer.scheduledTimer(timeInterval: 1, target:self, selector: #selector(ViewController.updateCounter), userInfo: nil, repeats: true)
        }

Code for second view controller:

import UIKit

class ContinueScreen: UIViewController {    
//correct answer label
@IBOutlet weak var correctLbl: UILabel!
//background photo
@IBOutlet weak var backgroundImage: UIImageView!

func backToQuiz() {
    performSegue(withIdentifier: "continueSeg", sender: self)
}

@IBAction func `continue`(_ sender: Any) {
    backToQuiz()
}

override func viewDidLoad() {
    super.viewDidLoad()
}
Museer Ahamad Ansari
  • 4,939
  • 2
  • 35
  • 43
Captain Code
  • 207
  • 3
  • 12
  • Use an object to store your data and refer to one instance of it from your relevant view controllers; Also, make sure that `continueSeg` is an [*unwind segue*](https://stackoverflow.com/questions/12561735/what-are-unwind-segues-for-and-how-do-you-use-them) – Paulw11 Jul 25 '17 at 06:53
  • How to unwind segues differ from regular segues? – Captain Code Jul 25 '17 at 07:36
  • You can search for information; Apple has a very good tech note on them. Basically, an unwind segue goes back to an existing view controller instance – Paulw11 Jul 25 '17 at 08:34

2 Answers2

1

You will need to implement delegates for that. You can find more information here.

Your question is related to this.

Please go through that. Hope that helps.

Mohammad Sadiq
  • 4,041
  • 25
  • 25
  • I think the problem is not the transferral of data between view controllers back and forth, but the creation of a new instance of the parent view controller in `backToQuiz` – Andreas Oetjen Jul 25 '17 at 06:44
  • How could I prevent a new instance of view controller? – Captain Code Jul 25 '17 at 06:55
  • No, why new instance would be created. Make a note that in Swift Arrays are value type. So by default if you copy the array a new instance get created and all the elements get copied into that one. Whatever changes you will do would be done on the new copy and not get propagated to the array from which it was copied. – Mohammad Sadiq Jul 25 '17 at 06:56
  • 1
    The second view controller isn't using the array at all, so it is *not* copied anywhere. The problem is that a *new viewcontroller* is created in `backToQuiz` instead of returning to the first one. – Andreas Oetjen Jul 25 '17 at 07:11
  • a new viewcontroller is not created. You can check that in console. Problem is in your logic somewhere. One place I can see is that you are making questionsArray empty for every wrong answer. And its refilling the array again on viewDidAppear.I don't know if its intended. – Mohammad Sadiq Jul 25 '17 at 07:20
  • Im just trying to make it to where I segue back to the original view controller questions that have been asked already aren't asked again after the segue takes place. If I take the segue out the code works how I intend it to – Captain Code Jul 25 '17 at 07:28
0

The problem is that you - when you return to the first view controller in backToQuiz() - call performSegue, which will then

  • create a new instance of the first view controller and
  • re-initialize it with the original (unmodified) quiz data

Instead, you should do something like

func backToQuiz() { 
   if let nav = self.navigationController {
        nav.popViewController(animated: true)
    } else {
        self.dismiss(animated: true, completion: nil)
    }
}

to return to the parent view controller instance.

Andreas Oetjen
  • 8,386
  • 1
  • 18
  • 30
  • So what's the best way to make sure a new instance of the view controller isn't created when using segues? – Captain Code Jul 25 '17 at 06:56
  • The way you go is to either pop the ViewController / dismiss the current one, as shown above, or take a look at segue unwinding as mentioned by @Paulw11 in the comment above. – Andreas Oetjen Jul 25 '17 at 07:16
  • Thank you for you're insight! Really helpful.. I implemented your code and it doesn't do exactly what im going for but I think its a step in the right direction. – Captain Code Jul 25 '17 at 07:34