Fatal error: Index out of range, in the line where I try to some value to an array

Error message when running the application with the simulator.

Fatal error: Index out of range, in the line where I try to some value to an array

I really hope you have an answer for me


Here is my code


import UIKit


class ViewController: UIViewController {


@IBOutlet weak var questionTextView: UITextView!

@IBOutlet weak var judgement: UILabel!

@IBOutlet weak var ans1: UIButton!

@IBOutlet weak var ans2: UIButton!

@IBOutlet weak var ans3: UIButton!

@IBOutlet weak var ans4: UIButton!



var question = ""

var CorAns = 0


var quizData: [Any] = []


override func viewDidLoad() {

super.viewDidLoad()

// Do any additional setup after loading the view.


loadJsonFile()

updateQA()

}


func updateQA() {


let index = Int.random(in: 0...10)


let quizObject = quizData[index] as! Dictionary<String,Any> // ===> Thread 1: Fatal error: Index out of range


question = quizObject["question"] as! String

questionTextView.text = question


let correctAns: String = quizObject["correct_answer"] as! String

let wrongAns: [String] = quizObject["incorrect_answers"] as! [String]


let correctIndex: Int = Int.random(in: 0...3)


switch correctIndex {

case 0:

CorAns = 0

ans1.setTitle(correctAns, for: .normal)

ans2.setTitle(wrongAns[0], for: .normal)

ans3.setTitle(wrongAns[1], for: .normal)

ans4.setTitle(wrongAns[2], for: .normal)

case 1:

CorAns = 1

ans2.setTitle(correctAns, for: .normal)

ans1.setTitle(wrongAns[0], for: .normal)

ans3.setTitle(wrongAns[1], for: .normal)

ans4.setTitle(wrongAns[2], for: .normal)

case 2:

CorAns = 2

ans3.setTitle(correctAns, for: .normal)

ans2.setTitle(wrongAns[0], for: .normal)

ans1.setTitle(wrongAns[1], for: .normal)

ans4.setTitle(wrongAns[2], for: .normal)

case 3:

CorAns = 3

ans4.setTitle(correctAns, for: .normal)

ans2.setTitle(wrongAns[0], for: .normal)

ans3.setTitle(wrongAns[1], for: .normal)

ans1.setTitle(wrongAns[2], for: .normal)

default:

print("Error")

}


judgement.text = "Select Any One"

judgement.textColor = UIColor.black

}


private func loadJsonFile() {

do {

if let file = Bundle.main.url(forResource: "quiz", withExtension: "json") {

let data = try Data(contentsOf: file)

let json = try JSONSerialization.jsonObject(with: data, options: [])

if let object = json as? [String: Any] {

// json is a dictionary

print("As Dictionary \(object)")

} else if let object = json as? [Any] {

// json is an array

print("As Array \(object)")

quizData = object

} else {

print("JSON is invalid")

}

} else {

print("no file")

}

} catch {

print(error.localizedDescription)

}

}


func correctAns() {


UIView.animate(withDuration: 1, animations: {

self.judgement.alpha = 0

}) { (complete) in

self.judgement.text = "Correct Answer"

self.judgement.textColor = UIColor.green


UIView.animate(withDuration: 1, animations: {

self.judgement.alpha = 1

}, completion: { (complete) in


DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {

self.updateQA()

})

})

}


}


func wrongAns() {


UIView.animate(withDuration: 1, animations: {

self.judgement.alpha = 0

}) { (complete) in

self.judgement.text = "Wrong Answer"

self.judgement.textColor = UIColor.red


UIView.animate(withDuration: 1, animations: {

self.judgement.alpha = 1

}, completion: { (complete) in


DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {

self.updateQA()

})

})

}

}


@IBAction func ans1Pressed(_ sender: Any) {


if (CorAns == 0) {

correctAns()

} else {

wrongAns()

}

}


@IBAction func ans2Pressed(_ sender: Any) {


if (CorAns == 1) {

correctAns()

} else {

wrongAns()

}

}


@IBAction func ans3Pressed(_ sender: Any) {


if (CorAns == 2) {

correctAns()

} else {

wrongAns()

}

}


@IBAction func ans4Pressed(_ sender: Any) {


if (CorAns == 3) {

correctAns()

} else {

wrongAns()

}

}

}

Accepted Reply

Well, that mean you have nothing in the dataArray.


You did not show what the print get on console.


To avoid a crash, you should change as:


    func updateQA() {
        if quizData.count == 0 { print("No data loaded" ; return }
        let index = Int.random(in: 0 ..< quizData.count)



Root cause is probably here:


    private func loadJsonFile() { 
        do { 
            if let file = Bundle.main.url(forResource: "quiz", withExtension: "json") { 
                let data = try Data(contentsOf: file) 
                let json = try JSONSerialization.jsonObject(with: data, options: []) 
                if let object = json as? [String: Any] { 
                    // json is a dictionary 
                    print("As Dictionary \(object)") 
                } else if let object = json as? [Any] { 
                    // json is an array 
                    print("As Array \(object)") 
                    quizData = object 
                     
                } else { 
                    print("JSON is invalid") 
                } 
            } else { 
                print("no file") 
            } 
        } catch { 
            print(error.localizedDescription) 
        } 
    }


Line 8, you don't load object into dataArray as you do line 11. Is it intentional ?


Please, once again, show the print outputs.

Replies

When you post code, please use the code formatting (<>). That allows to reference code by line.


Which line is your error ? Line 30 ?

You should also post what you get with the print statements (all): that helps a lot investigation, otherwise we just have to guess.


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var questionTextView: UITextView!
    @IBOutlet weak var judgement: UILabel!
    @IBOutlet weak var ans1: UIButton!
    @IBOutlet weak var ans2: UIButton!
    @IBOutlet weak var ans3: UIButton!
    @IBOutlet weak var ans4: UIButton!


    var question = ""
    var CorAns = 0

    var quizData: [Any] = []

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.

        loadJsonFile()
        updateQA()
    }

    func updateQA() {

        let index = Int.random(in: 0...10)

        let quizObject = quizData[index] as! Dictionary<string,any>        //  ===> Thread 1: Fatal error: Index out of range

        question = quizObject["question"] as! String
        questionTextView.text = question

        let correctAns: String = quizObject["correct_answer"] as! String
        let wrongAns: [String] = quizObject["incorrect_answers"] as! [String]

        let correctIndex: Int = Int.random(in: 0...3)

        switch correctIndex {
        case 0:
            CorAns = 0
            ans1.setTitle(correctAns, for: .normal)
    
            ans2.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
    
            case 1:
            CorAns = 1
            ans2.setTitle(correctAns, for: .normal)
    
            ans1.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
    
            case 2:
            CorAns = 2
            ans3.setTitle(correctAns, for: .normal)
    
            ans2.setTitle(wrongAns[0], for: .normal)
            ans1.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
    
            case 3:
            CorAns = 3
            ans4.setTitle(correctAns, for: .normal)
    
            ans2.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans1.setTitle(wrongAns[2], for: .normal)
    
        default:
            print("Error")
        }

        judgement.text = "Select Any One"
        judgement.textColor = UIColor.black
    }

    private func loadJsonFile() {
        do {
            if let file = Bundle.main.url(forResource: "quiz", withExtension: "json") {
                let data = try Data(contentsOf: file)
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                if let object = json as? [String: Any] {
                    // json is a dictionary
                    print("As Dictionary \(object)")
                } else if let object = json as? [Any] {
                    // json is an array
                    print("As Array \(object)")
                    quizData = object
            
                } else {
                    print("JSON is invalid")
                }
            } else {
                print("no file")
            }
        } catch {
            print(error.localizedDescription)
        }
    }

    func correctAns() {

        UIView.animate(withDuration: 1, animations: {
            self.judgement.alpha = 0
        }) { (complete) in
            self.judgement.text = "Correct Answer"
            self.judgement.textColor = UIColor.green

        UIView.animate(withDuration: 1, animations: {
            self.judgement.alpha = 1
          }, completion: { (complete) in

            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                self.updateQA()
            })
         })
       }

    }

    func wrongAns() {

        UIView.animate(withDuration: 1, animations: {
             self.judgement.alpha = 0
         }) { (complete) in
             self.judgement.text = "Wrong Answer"
             self.judgement.textColor = UIColor.red
 
         UIView.animate(withDuration: 1, animations: {
             self.judgement.alpha = 1
           }, completion: { (complete) in
 
             DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                 self.updateQA()
             })
          })
        }
    }

    @IBAction func ans1Pressed(_ sender: Any) {

        if (CorAns == 0) {
            correctAns()
        } else {
            wrongAns()
        }
    }

    @IBAction func ans2Pressed(_ sender: Any) {

        if (CorAns == 1) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }

    @IBAction func ans3Pressed(_ sender: Any) {

        if (CorAns == 2) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }

    @IBAction func ans4Pressed(_ sender: Any) {

        if (CorAns == 3) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }
}



Line 30, you assume that quizData has at least 11 elements. How are you sure ? May you have just 10, so if random give 10, you're out of bounds.


You should change line 30 as:

        let index = Int.random(in: 0 ..< quizData.count)

Thanks, Claude31 for your help, but the problem persist

Error in line 28 Thread 1: Fatal error: Can't get random value with an empty range


import UIKit

class ViewController: UIViewController {

    @IBOutlet weak var questionTextView: UITextView!
    @IBOutlet weak var judgement: UILabel!
    @IBOutlet weak var ans1: UIButton!
    @IBOutlet weak var ans2: UIButton!
    @IBOutlet weak var ans3: UIButton!
    @IBOutlet weak var ans4: UIButton!
    
    
    var question = ""
    var CorAns = 0
    
    var quizData: [Any] = []
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        loadJsonFile()
        updateQA()
    }
    
    func updateQA() {
        
        let index = Int.random(in: 0 ..< quizData.count)
        
        let quizObject = quizData[index] as! Dictionary<String,Any>
        
        question = quizObject["question"] as! String
        questionTextView.text = question
        
        let correctAns: String = quizObject["correct_answer"] as! String
        let wrongAns: [String] = quizObject["incorrect_answers"] as! [String]
        
        let correctIndex: Int = Int.random(in: 0...3)
        
        switch correctIndex {
        case 0:
            CorAns = 0
            ans1.setTitle(correctAns, for: .normal)
            
            ans2.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
            
            case 1:
            CorAns = 1
            ans2.setTitle(correctAns, for: .normal)
            
            ans1.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
            
            case 2:
            CorAns = 2
            ans3.setTitle(correctAns, for: .normal)
            
            ans2.setTitle(wrongAns[0], for: .normal)
            ans1.setTitle(wrongAns[1], for: .normal)
            ans4.setTitle(wrongAns[2], for: .normal)
            
            case 3:
            CorAns = 3
            ans4.setTitle(correctAns, for: .normal)
            
            ans2.setTitle(wrongAns[0], for: .normal)
            ans3.setTitle(wrongAns[1], for: .normal)
            ans1.setTitle(wrongAns[2], for: .normal)
            
        default:
            print("Error")
        }
        
        judgement.text = "Select Any One"
        judgement.textColor = UIColor.black
    }
    
    private func loadJsonFile() {
        do {
            if let file = Bundle.main.url(forResource: "quiz", withExtension: "json") {
                let data = try Data(contentsOf: file)
                let json = try JSONSerialization.jsonObject(with: data, options: [])
                if let object = json as? [String: Any] {
                    // json is a dictionary
                    print("As Dictionary \(object)")
                } else if let object = json as? [Any] {
                    // json is an array
                    print("As Array \(object)")
                    quizData = object
                    
                } else {
                    print("JSON is invalid")
                }
            } else {
                print("no file")
            }
        } catch {
            print(error.localizedDescription)
        }
    }
    
    func correctAns() {
        
        UIView.animate(withDuration: 1, animations: {
            self.judgement.alpha = 0
        }) { (complete) in
            self.judgement.text = "Correct Answer"
            self.judgement.textColor = UIColor.green
        
        UIView.animate(withDuration: 1, animations: {
            self.judgement.alpha = 1
          }, completion: { (complete) in
        
            DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                self.updateQA()
            })
         })
       }
    
    }
    
    func wrongAns() {
        
        UIView.animate(withDuration: 1, animations: {
             self.judgement.alpha = 0
         }) { (complete) in
             self.judgement.text = "Wrong Answer"
             self.judgement.textColor = UIColor.red
         
         UIView.animate(withDuration: 1, animations: {
             self.judgement.alpha = 1
           }, completion: { (complete) in
         
             DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
                 self.updateQA()
             })
          })
        }
    }
    
    @IBAction func ans1Pressed(_ sender: Any) {
        
        if (CorAns == 0) {
            correctAns()
        } else {
            wrongAns()
        }
    }
    
    @IBAction func ans2Pressed(_ sender: Any) {
        
        if (CorAns == 1) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }
    
    @IBAction func ans3Pressed(_ sender: Any) {
        
        if (CorAns == 2) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }
    
    @IBAction func ans4Pressed(_ sender: Any) {
        
        if (CorAns == 3) {
                 correctAns()
             } else {
                 wrongAns()
             }
    }
}

Well, that mean you have nothing in the dataArray.


You did not show what the print get on console.


To avoid a crash, you should change as:


    func updateQA() {
        if quizData.count == 0 { print("No data loaded" ; return }
        let index = Int.random(in: 0 ..< quizData.count)



Root cause is probably here:


    private func loadJsonFile() { 
        do { 
            if let file = Bundle.main.url(forResource: "quiz", withExtension: "json") { 
                let data = try Data(contentsOf: file) 
                let json = try JSONSerialization.jsonObject(with: data, options: []) 
                if let object = json as? [String: Any] { 
                    // json is a dictionary 
                    print("As Dictionary \(object)") 
                } else if let object = json as? [Any] { 
                    // json is an array 
                    print("As Array \(object)") 
                    quizData = object 
                     
                } else { 
                    print("JSON is invalid") 
                } 
            } else { 
                print("no file") 
            } 
        } catch { 
            print(error.localizedDescription) 
        } 
    }


Line 8, you don't load object into dataArray as you do line 11. Is it intentional ?


Please, once again, show the print outputs.