Safe get a value from an array in Swift

Subscribe to my newsletter and never miss my upcoming articles

Hello people, Leo here.

Today we'll explore how can we get values from array but avoiding crashes in your app. Image explanation: array safe get with the bank safe, it's all about the safeness. Got it? (:

So let's go!

Problem

I want to get a value from array but I don't want by any chance get an array out of bounds error.

First let's examine the below code:

let nameList = ["Ana","Leo","Bob"]

print(nameList[3])

Arrays in Swift are zero-based, that means we're trying to print the fourth element of the nameList. If you run the above code you get an:

Screen Shot 2020-10-15 at 08.28.09.png

So how can we be sure when accessing an array that the index/element is there?

If you know what you are searching for, you can use contains() method that will return a Boolean if it's there or not:

let nameList = ["Ana","Leo","Bob"]
nameList.contains("Ana") // returns true

You can check if the index that you're searching for is between the existing index inside the array, like the code below show:

let targetIndex = 3

if nameList.startIndex <= targetIndex && targetIndex < nameList.endIndex {
    print(nameList[targetIndex])
} else {
    print("can't get from array because index out of bounds")
}

And furthermore you can extract the if code to a func to be more readable:

func isValid(index: Int, to array: [Any]) -> Bool {
    array.startIndex <= index && index < array.endIndex
}

if isValid(index: targetIndex, to: nameList) {
    print(nameList[targetIndex])
} else {
    print("can't get from array because index out of bounds")
}

This works great and if you aren't dealing with a lot of arrays in your codebase can be a way to go. However, we can improve this just using a custom extension subscript to the array, this way all arrays in the code could utilize this feature. The code below is one way to do that:

extension Array {

    subscript(safe index: Int) -> Element? {
        guard index < endIndex, index >= startIndex else { return nil}
        return self[index]
    }

}

The drawback of this approach is this subscript returns an optional so you'll have to do the nil check after.

And that's it. I hope you enjoy this as much as I enjoyed writing and any feedback are much appreciated.

Thanks for the reading and... That's all folks.

Credits: Image

Comments (2)

Cícero Camargo's photo

Hi Leonardo! First of all, congrats for the quality and consistency of your articles.

One last step would be to use the indices range with its operators, like this:

extension Array {
    subscript(safe index: Int) -> Element? {
        guard indices ~= index else { return nil }
        return self[index]
    }
}

I think it's shorter and more elegant, but still very readable. I hope you like it.

Leonardo Maia Pugliese's photo

Great comment Cicero, I don't even know what are this ˜= operator in Swift, I'll study more for sure.