George Schena
George Schena

Reputation: 21

Empty array causing my app to crash in Swift

I keep coming across this error "fatal error: Index out of range", after researching this I am still unsure of exactly how to fix this issue. To give context I have started off with an empty array var playersArray = [UITextField]() so that users can enter their names in order to play the game. I then make sure that the user has or has not entered a value into the text field for each name slot

if let player1Name = name1.text, !player1Name.isEmpty
        {   playersArray.append(name1)

        } else {
            print("Player 1 Empty")

If the player has entered a value into that textfield then ill append that value to the array. The issue I have is that if I run the game and no user has entered a name into any of the 10 textfields then the game will crash. Im assuming this is because the array is empty?

The error appears on this line where I randomize the names used for the game with the number of elements in the array:

 let RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]

I assume if the array is empty then .count will not work?

How can I make sure the game wont crash if the array is empty?

CODE:

 var playersArray = [UITextField]()

    override func viewDidLoad() {
        super.viewDidLoad()
        textColor()
        question1View.isHidden = true
        questionLabel.transform = CGAffineTransform(rotationAngle: CGFloat.pi / 2)


    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }

    // Alert message on startup
    func alertMessageOnStartUp(){
        let alert = UIAlertController(title: "Warning!", message: "Please drink responsibly. By continuing, you agree that you are responsible for any consequences that may result from BottomsUp.", preferredStyle: UIAlertControllerStyle.alert)
        alert.addAction(UIAlertAction(title: "Agree", style: UIAlertActionStyle.default, handler: nil))
        self.present(alert, animated: true, completion: nil)
    }

    // Dismiss keyboard when tapped outside the keyboard
    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

    // Dimiss keybaord when return button is tapped
    func textFieldShouldReturn(_ textField: UITextField) -> Bool {
        name1.resignFirstResponder()
        name2.resignFirstResponder()
        name3.resignFirstResponder()
        name4.resignFirstResponder()
        name5.resignFirstResponder()
        name6.resignFirstResponder()
        name7.resignFirstResponder()
        name8.resignFirstResponder()
        name9.resignFirstResponder()
        name10.resignFirstResponder()
        return(true)
    }

    //randomise background colour of each question page
    func getRandomBackgroundColor() -> UIColor{
        let randomRed:CGFloat = CGFloat(drand48())
        let randomGreen:CGFloat = CGFloat(drand48())
        let randomBlue:CGFloat = CGFloat(drand48())
        return UIColor(red: randomRed, green: randomGreen, blue: randomBlue, alpha: 1.0)
    }

        func textColor(){
        name1.textColor = UIColor.white
        name2.textColor = UIColor.white
        name3.textColor = UIColor.white
        name4.textColor = UIColor.white
        name5.textColor = UIColor.white
        name6.textColor = UIColor.white
        name7.textColor = UIColor.white
        name8.textColor = UIColor.white
        name9.textColor = UIColor.white
        name10.textColor = UIColor.white
    }

    @IBAction func playButton(_ sender: Any) {
        alertMessageOnStartUp()

        if let player1Name = name1.text, !player1Name.isEmpty
        {   playersArray.append(name1)

        } else {
            print("Player 1 Empty")
        }

        if let player2Name = name2.text, !player2Name.isEmpty
        {   playersArray.append(name2)

        } else {
            print("Player 2 Empty")
        }

        if let player3Name = name3.text, !player3Name.isEmpty
        {   playersArray.append(name3)

        } else {
            print("Player 3 Empty")
        }

        if let player4Name = name4.text, !player4Name.isEmpty
        {   playersArray.append(name4)

        } else {
            print("Player 4 Empty")
        }

        if let player5Name = name5.text, !player5Name.isEmpty
        {   playersArray.append(name5)

        } else {
            print("Player 5 Empty")
        }

        if let player6Name = name6.text, !player6Name.isEmpty
        {   playersArray.append(name6)

        } else {
            print("Player 6 Empty")
        }

        if let player7Name = name7.text, !player7Name.isEmpty
        {   playersArray.append(name7)

        } else {
            print("Player 7 Empty")
        }

        if let player8Name = name8.text, !player8Name.isEmpty
        {   playersArray.append(name8)

        } else {
            print("Player 8 Empty")
        }

        if let player9Name = name9.text, !player9Name.isEmpty
        {   playersArray.append(name9)

        } else {
            print("Player 9 Empty")
        }

        if let player10Name = name10.text, !player10Name.isEmpty
        {   playersArray.append(name10)

        } else {
            print("Player 10 Empty")
        }

        question1View.isHidden = false
        question1View.backgroundColor = getRandomBackgroundColor()


        let RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
        let RandomQuestion = questionArray[Int(arc4random_uniform(UInt32(questionArray.count)))]
        questionLabel.text = RandomPlayer.text! + RandomQuestion

    }

    @IBAction func nextQuestionButton(_ sender: Any) {
        question1View.backgroundColor = getRandomBackgroundColor()

        let RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
        let RandomQuestion = questionArray[Int(arc4random_uniform(UInt32(questionArray.count)))]
        questionLabel.text = RandomPlayer.text! + RandomQuestion
    }
}

Upvotes: 0

Views: 2676

Answers (2)

user94559
user94559

Reputation: 60143

Breaking this down:

Int(arc4random_uniform(UInt32(playersArray.count)))

This line gets a random number with a minimum value of 0 and a maximum value of the length of the playersArray minus 1.

I'm actually not sure what it does when the argument you pass in is 0, but it doesn't really matter, as we'll see next.

Then you use that random value here:

playersArray[thatRandomNumber]

Because there are no elements in playersArray, no matter what the value is of thatRandomNumber, it's going to be out of bounds.

You probably want something more like this:

let RandomPlayer = <some default value>
if !playersArray.isEmpty {
    RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
}

EDIT

Your latest code still doesn't seem to do anything to prevent indexing into the empty array.

You have:

@IBAction func playButton(_ sender: Any) {
    ...
    let RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
    let RandomQuestion = questionArray[Int(arc4random_uniform(UInt32(questionArray.count)))]
    questionLabel.text = RandomPlayer.text! + RandomQuestion
}

You need:

@IBAction func playButton(_ sender: Any) {
    ...
    if playersArray.isEmpty {
         // do something about that
    } else {
        let RandomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
        let RandomQuestion = questionArray[Int(arc4random_uniform(UInt32(questionArray.count)))]
        questionLabel.text = RandomPlayer.text! + RandomQuestion
    }
}

Upvotes: 1

JAB
JAB

Reputation: 3235

playersArray.count for an empty array is 0, so you are trying to access playersArray[0] - but the array is empty, so nothing exists at the 0 index.

You should do something like this:

let randomPlayer: Player
if !playersArray.isEmpty {
   randomPlayer = playersArray[Int(arc4random_uniform(UInt32(playersArray.count)))]
} else {
   randomPlayer = Player() //create a fallback player
}

Alternatively you could make randomPlayer an optional, rather than providing a fallback value. Depends on your needs for that variable.

Upvotes: 0

Related Questions