Question related to endIndex

I am very new to Swift and I have a question about the array method endIndex. Here are some sample code.

import UIKit

class ViewController: UIViewController {

let ballImages = [UIImage(named: "ball1"),UIImage(named: "ball2"),UIImage(named:    "ball3"),UIImage(named: "ball4"),UIImage(named: "ball5")]

@IBOutlet weak var imageView: UIImageView!

@IBAction func askButtonPressed(_ sender: UIButton) {
    imageView.image = ballImages[Int.random(in: 0 ..< ballImages.endIndex)]

so when I first ran this code I expected the endIndex to return the last index in the array a.k.a 4 from the ballImages array, but it returns 5? So I had to change
Int.random(in: 0 ... ballImages.endIndex)
Int.random(in: 0 ..< ballImages.endIndex)

it kinda threw me off. Am I missunderstanding something here or does the endIndex really return the length and not really the index?

Thanks for any assistance

You can read endIndex's documentation here. As it says, it's the "past the end" position for a Collection. I think it's defined like that so it's useful for both the full range of indices (startIndex ..< endIndex) as well as what the next index should be, but I'll let someone with more expertise confirm the reason why.

1 Like

Also the thing about index, is that the integer mental model ends quickly once you use something other than Array.

Array is the only instance that guarantees that first index is 0, the index after is 1, and so on. Other types has a lot of freedom to do something else. Such as Set, Dictionary which use their own struct as index. Even if some type use Int, it's not guaranteed to start with 0, and increase by 1.


It's also nice to have an invalid index at the end, as one can easily write

while index < collection.endIndex {

which is not easy to do if you have lastIndex instead of endIndex.

1 Like

Symbols starting with last describe the final index valid for taking (or swapping) things out:

var array = ["A", "B", "C", "D", "E"]
assert(array[array.indices.last!] == "E")

Symbols starting with end describe the final index valid for putting new things in:

array.insert("F", at: array.endIndex)
assert(array == ["A", "B", "C", "D", "E", "F"])

Notice why the two have to be different:

array.insert("G", at: array.indices.last!)
print(array) // ["A", "B", "C", "D", "E", "G", "F"] ?!?

print(array[array.endIndex]) // Fatal error: Index out of bounds.

Conceptually “last” sort of refers to the equivalent of fence panels, whereas “end” sort of refers to the equivalent of fence posts (of which there is always one more). See Fencepost Arithmetic.


Although not answering your question, which probably just served as an example—however, you could avoid the whole issue using:

imageView.image = ballImages.randomElememt()

Thank you for the insight.