The below code gives me an error. Is there a way to simply have this return nil?
var testArray: [Int]?
testArray = [1,2,3]
testArray?[9]
There are 3 possible things here that you might be conflating:
[Int]?[Int?]subscript(index) -> Int?.What you've got in your example is the first case – an optional of an array. That is, either testArray is nil, or it's a valid array containing zero or more elements.
To access anything inside an optional you have to first unwrap it. You can either force-unwrap it with ! (Try not to do this unless you have a really good reason – no not that reason. No not that one either). Or you can conditionally unwrap it, either using if let, or using one of the operators like ?, ?., ?? etc. In this case, testArray?[9] means, "if testArray is nil, then nil, otherwise {Some whatever is at position 9}. But there is no value at position 9 – this is only a 3-element array. So you get a runtime assertion.
(Another way of writing testArray?[9] would be testArray.map { $0[9] }, where inside the block the array is unwrapped and valid, but if it’s nil the block never gets executed. But the result is still that you try to access the 9th element of the array, and that's not allowed and you get a runtime error)
The second case, an array of optional integers, would mean that you could access testArray[1] and you'd get back {Some 2}, because the array holds optionals. But again, you can't access the 9th element, because there is no 9th element.
Finally the third case is where calling subscript gives you back an optional value, and if it's not a valid index, you get back a nil. This seems to be what you were expecting. Swift arrays do not do this. Swift dictionaries do, if you are looking up by key. If the key has a value, you get back {Some value}, if not, you get nil. The shorthand justification for this is that dictionaries contain sparse data, whereas arrays contain dense data.
If you're interested, I wrote posts about both the pro and anti argument for making arrays return optionals from subscript. But for now, like the other answers say, you have to check your bounds before accessing elements. You might want to try some of the helper methods like first, last, find, as well as map and filter etc rather than accessing elements directly, as this makes many of these problems go away.
(another interesting thing to think about – all 3 cases above can be combined together. So you could have an optional dictionary of optionals, that returned optionals when you accessed it. If you're still hazy on all this, try playing around with that in a playground :)
You need to do the range check explicitly, like this:
var testArray: [Int]?
testArray = [1,2,3]
let index1 = 9
let numberNine : Int? = index1 < testArray!.count ? testArray![ index1 ] : nil
println(numberNine)
let index2 = 2
let numberTwo : Int? = index2 < testArray!.count ? testArray![ index2 ] : nil
println(numberTwo!)
Conditional expression ... ? ... : ... will check the condition before deciding what side of the : to evaluate, so testArray![ index1 ] is protected by the condition: it will not cause an exception when the index is out of range.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With