Start learning free

LESSON 102 OF 415 · ARRAYS I

Exceeding Array Bounds in Swift

Lesson Read the full explanation

When accessing Array data with indices, the most common problem we can run into is exceeding the Array's bounds.

Remember, the items of an Array are indexed from 0 to count - 1. Any index which is not in this range is invalid.

When you try to access an item with an invalid index, Swift stops the program with a fatal error (it is not an error you can catch):

var ourArray = [50, 40, 30]

// Valid indices: 0, 1, 2
print(ourArray[0]) // Output: 50
print(ourArray[2]) // Output: 30

// Invalid indices: 3, 30, -1
print(ourArray[3]) // Fatal error: Index out of range
print(ourArray[30]) // Fatal error: Index out of range
print(ourArray[-1]) // Fatal error: Index out of range

As programmers, we always want to make sure that we don't exceed one Array's bounds in our programs.


Assignment
Follow the Coding Tutorial and let's play with some arrays.


Hint
Look at the examples above if you get stuck.


STEP 1 OF 1
    Ctrl + Enter to check

    SWIFT · ARRAYS I

    Exceeding Array Bounds in Swift, explained

    The bounds of an array

    An array's items are indexed from 0 to count - 1. This range is the array's bounds, and any index outside it is invalid. Exceeding the bounds is the most common problem when using indexes.

    var ourArray = [50, 40, 30]
    
    // Valid indexes: 0, 1, 2
    print(ourArray[0])  // 50
    print(ourArray[2])  // 30
    

    For this array the indexes 3 and 30 are past the end and -1 is before the start. Swift does not read from the end when you give it a negative number.

    What Swift does

    Swift checks every array access. When the index is invalid, it stops the program with a fatal error, usually described as "Index out of range". The error is not thrown in the sense of throw and try, so a do/catch block can't handle it. The program ends there, and the lines after the failing one don't run. This is a safety feature: the program never reads memory that doesn't belong to the array.

    The same happens when you assign to an invalid index. A subscript only replaces an element that exists, so ourArray[3] = 5 on a three-element array crashes. Use append to add an element.

    The exercise: find the mistake

    This program should print the last element of ages, which is 21:

    var ages = [14, 32, 50, 21]
    
    print(ages[ages.count])
    

    Instead it crashes. To find the bug, look at the index on the line that prints.

    1. Evaluate the index. ages.count is 4, so the code reads ages[4].
    2. List the valid indexes. Four elements occupy indexes 0, 1, 2 and 3. Index 4 doesn't exist.
    3. Move one step back. The last element is at ages.count - 1.
    var ages = [14, 32, 50, 21]
    
    print(ages[ages.count - 1])
    

    This prints 21.

    Avoiding the crash

    The mistake is easy to repeat with an index that is computed, so check it first:

    let index = 4
    if index < ages.count {
        print(ages[index])
    } else {
        print("out of range")  // this branch runs
    }
    

    Also test for a negative index, or use ages.indices.contains(index), which checks both ends. The first and last properties return optionals and give nil on an empty array, so they never crash. Loops written as for i in 0..<ages.count stay within the bounds, because the upper bound of ..< is excluded.

    Reading a crash report

    A crash like this is easy to fix once you know where to look. The failing line is the one that contains a subscript, so start with the number between the brackets and work out its value. If it comes from a variable or a calculation, evaluate it by hand with the array's real size. Then compare the result with the range 0 to count - 1. In most cases the index is off by one, or the array is shorter than the code assumed, for example because it is empty or because items were removed earlier.

    Common mistakes

    • Treating the count as an index. With four elements, 4 is a count, and the last index is 3.
    • Using ... in a loop. 0...ages.count includes 4. Use 0..<ages.count.
    • Expecting negative indexes to work. ages[-1] crashes.
    • Empty arrays. Nothing is a valid index there, and count - 1 is -1.
    • Forgetting that removing shrinks the array. After remove(at:), the indexes you used before may no longer exist.

    Key takeaways

    • Valid indexes go from 0 to count - 1.
    • An invalid index stops the program with a fatal error, and it can't be caught.
    • Use array[array.count - 1] for the last element.
    • Validate indexes that come from variables.
    Keep going with SwiftAbout 340 step-by-step lessons, from your first line of code to coding interviews. Free to start.
    Start learning free