In the docs, there's an example of an extension to add safe and unknowing access to any index (real or imagined) of a Swift array (Edit - SO Docs is now defunct so this example was inserted at the bottom of this question).
Swift arrays normally crash if the index doesn't exist. It seems this extension is explicitly designed to solve this problem by returning nil
if there's nothing at the index requested.
The extension looks like this:
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
Use of the extension looks like this:
if let thirdValue = array[safe: 2] {
print(thirdValue)
}
Trying this out in playgrounds reveals nothing coming back for an unsafe index. That I can tell. Not an optional, not a nil, nothing. And no crash.
How is this not an optional that's coming back from this when it's a safe or unsafe index value? I admire that this works, just don't really understand how it works, or what it's doing.
As Martin R helpfully points out, most of my problem is not understanding/remembering/knowing that if let
is doing a forceful unwrapping of the optional that results from the extension's function returning a value that is most definitely an Optional. If this forceful unwrapping fails to divulge a value (ie no value at the index returns an optional containing nil
) this prevents the {trailing closure}
from being invoked.
However it brings up another subquestion.
If using a variable to capture the return value, like so:
let val = array[safe: 2]
print("val:", val)
regardless of the result, it is an optional, but Swift provides a "helpful" error saying:
Expression implicitly coerced from 'Int?' to Any
I apologise if this should be a new question: Why is this being coerced to Any
? Why can't (and why doesn't it) simply remain as an Optional of type Int?
The following content is from "Accessing indices safely" from Stack Overflow Documentation (archived here); copyright 2017 by Moriya; licensed under CC BY-SA 3.0. An archive of the full Stack Overflow Documentation content can be found at archive.org, in which this example is indexed by its topic ID: 284, as example: 16567.
By adding the following extension to array indices can be accessed without knowing if the index is inside bounds.
extension Array {
subscript (safe index: Int) -> Element? {
return indices ~= index ? self[index] : nil
}
}
example:
if let thirdValue = array[safe: 2] {
print(thirdValue)
}
if let val = someOptional { ... }
is an optional binding. If someOptional != nil
then the condition
is true and the unwrapped value someOptional!
is assigned to val
.
If someOptional == nil
then the condition is false.
So in your case
if let thirdValue = array[safe: 2] {
print(thirdValue)
}
the condition is true (and the if-block executed) if array[safe: 2] != nil
. In that case, the unwrapped value is assigned to thirdValue
.
On the other hand, if array[safe: 2]
returns nil
then the condition
is false and the if-block is not executed.
You can print the return value without using an if-condition to verify
that it is nil
:
let array = [1, 2]
let val = array[safe: 2]
print("val:", val) // "val: nil"
With Swift 3.0.1 (Xcode 8.1, tested with GM seed) this will cause compiler warnings
main.swift:12:16: warning: expression implicitly coerced from 'Int?' to Any print("val:", val) ^~~ main.swift:12:16: note: provide a default value to avoid this warning print("val:", val) ^~~ ?? main.swift:12:16: note: force-unwrap the value to avoid this warning print("val:", val) ^~~ ! main.swift:12:16: note: explicitly cast to Any with 'as Any' to silence this warning print("val:", val) ^~~ as Any
as a consequence of the implementation of SE-0140 Warn when Optional converts to Any, and bridge Optional As Its Payload Or NSNull.
The warning can be suppressed with
print("val:", val as Any) // "val: nil"