46

Quite often, you need to write code such as the following:

if someOptional != nil {
    // do something with the unwrapped someOptional e.g.       
    someFunction(someOptional!)
}

This seems a bit verbose, and also I hear that using the ! force unwrap operator can be unsafe and best avoided. Is there a better way to handle this?

Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118

5 Answers5

115

It is almost always unnecessary to check if an optional is not nil. Pretty much the only time you need to do this is if its nil-ness is the only thing you want to know about – you don’t care what’s in the value, just that it’s not nil.

Under most other circumstances, there is a bit of Swift shorthand that can more safely and concisely do the task inside the if for you.

Using the value if it isn’t nil

Instead of:

let s = "1"
let i = Int(s)

if i != nil {
    print(i! + 1)
}

you can use if let:

if let i = Int(s) {
    print(i + 1)
}

You can also use var:

if var i = Int(s) {
    print(++i)  // prints 2
}

but note that i will be a local copy - any changes to i will not affect the value inside the original optional.

You can unwrap multiple optionals within a single if let, and later ones can depend on earlier ones:

if let url = NSURL(string: urlString),
       data = NSData(contentsOfURL: url),
       image = UIImage(data: data)
{
    let view = UIImageView(image: image)
    // etc.
}

You can also add where clauses to the unwrapped values:

if let url = NSURL(string: urlString) where url.pathExtension == "png",
   let data = NSData(contentsOfURL: url), image = UIImage(data: data)
{ etc. }

Replacing nil with a default

Instead of:

let j: Int
if i != nil {
    j = i
}
else {
    j = 0
}

or:

let j = i != nil ? i! : 0

you can use the nil-coalescing operator, ??:

// j will be the unwrapped value of i,
// or 0 if i is nil
let j = i ?? 0

Equating an optional with a non-optional

Instead of:

if i != nil && i! == 2 {
    print("i is two and not nil")
}

you can check if optionals are equal to non-optional values:

if i == 2 {
    print("i is two and not nil")
}

This also works with comparisons:

if i < 5 { }

nil is always equal to other nils, and is less than any non-nil value.

Be careful! There can be gotchas here:

let a: Any = "hello"
let b: Any = "goodbye"
if (a as? Double) == (b as? Double) {
    print("these will be equal because both nil...")
}

Calling a method (or reading a property) on an optional

Instead of:

let j: Int
if i != nil {
    j = i.successor()
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

you can use optional chaining, ?.:

let j = i?.successor()

Note, j will also now be optional, to account for the fatalError scenario. Later, you can use one of the other techniques in this answer to handle j’s optionality, but you can often defer actually unwrapping your optionals until much later, or sometimes not at all.

As the name implies, you can chain them, so you can write:

let j = s.toInt()?.successor()?.successor()

Optional chaining also works with subscripts:

let dictOfArrays: ["nine": [0,1,2,3,4,5,6,7]]
let sevenOfNine = dictOfArrays["nine"]?[7]  // returns {Some 7}

and functions:

let dictOfFuncs: [String:(Int,Int)->Int] = [
      "add":(+),
      "subtract":(-)
]

dictOfFuncs["add"]?(1,1)  // returns {Some 2}

Assigning to a property on an optional

Instead of:

if splitViewController != nil {
    splitViewController!.delegate = self 
}

you can assign through an optional chain:

splitViewController?.delegate = self

Only if splitViewController is non-nil will the assignment happen.

Using the value if it isn’t nil, or bailing (new in Swift 2.0)

Sometimes in a function, there’s a short bit of code you want to write to check an optional, and if it’s nil, exit the function early, otherwise keep going.

You might write this like this:

func f(s: String) {
    let i = Int(s)
    if i == nil { fatalError("Input must be a number") }
    print(i! + 1)
}

or to avoid the force unwrap, like this:

func f(s: String) {
    if let i = Int(s) {
        print(i! + 1)
    }
    else { 
        fatalErrr("Input must be a number")
    }
}

but it’s much nicer to keep the error-handling code at the top by the check. This can also lead to unpleasant nesting (the "pyramid of doom").

Instead you can use guard, which is like an if not let:

func f(s: String) {
    guard let i = Int(s)
        else { fatalError("Input must be a number") }

    // i will be an non-optional Int
    print(i+1)
}

The else part must exit the scope of the guarded value, e.g. a return or fatalError, to guarantee that the guarded value will be valid for the remainder of the scope.

guard isn’t limited to function scope. For example the following:

var a = ["0","1","foo","2"]
while !a.isEmpty  {
    guard let i = Int(a.removeLast())
        else { continue }

    print(i+1, appendNewline: false)
}

prints 321.

Looping over non-nil items in a sequence (new in Swift 2.0)

If you have a sequence of optionals, you can use for case let _? to iterate over all the non-optional elements:

let a = ["0","1","foo","2"]
for case let i? in a.map({ Int($0)}) {
    print(i+1, appendNewline: false)
}

prints 321. This is using the pattern-matching syntax for an optional, which is a variable name followed by ?.

You can also use this pattern matching in switch statements:

func add(i: Int?, _ j: Int?) -> Int? {
    switch (i,j) {
    case (nil,nil), (_?,nil), (nil,_?):
        return nil
    case let (x?,y?):
        return x + y
    }
}

add(1,2)    // 3
add(nil, 1) // nil

Looping until a function returns nil

Much like if let, you can also write while let and loop until nil:

while let line = readLine() {
    print(line)
}

You can also write while var (similar caveats to if var apply).

where clauses also work here (and terminate the loop, rather than skipping):

while let line = readLine() 
where !line.isEmpty {
    print(line)
}

Passing an optional into a function that takes a non-optional and returns a result

Instead of:

let j: Int
if i != nil {
    j = abs(i!)
}
else {
   // no reasonable action to take at this point
   fatalError("no idea what to do now...")
}

you can use optional’s map operator:

let j = i.map { abs($0) }

This is very similar to optional chaining, but for when you need to pass the non-optional value into the function as an argument. As with optional chaining, the result will be optional.

This is nice when you want an optional anyway. For example, reduce1 is like reduce, but uses the first value as the seed, returning an optional in case the array is empty. You might write it like this (using the guard keyword from earlier):

extension Array {
    func reduce1(combine: (T,T)->T)->T? {

        guard let head = self.first
            else { return nil }

        return dropFirst(self).reduce(head, combine: combine)
    }
}

[1,2,3].reduce1(+) // returns 6

But instead you could map the .first property, and return that:

extension Array {
    func reduce1(combine: (T,T)->T)->T? {
        return self.first.map {
            dropFirst(self).reduce($0, combine: combine)
        }
    }
}

Passing an optional into a function that takes an optional and returns a result, avoiding annoying double-optionals

Sometimes, you want something similar to map, but the function you want to call itself returns an optional. For example:

// an array of arrays
let arr = [[1,2,3],[4,5,6]]
// .first returns an optional of the first element of the array
// (optional because the array could be empty, in which case it's nil)
let fst = arr.first  // fst is now [Int]?, an optional array of ints
// now, if we want to find the index of the value 2, we could use map and find
let idx = fst.map { find($0, 2) }

But now idx is of type Int??, a double-optional. Instead, you can use flatMap, which “flattens” the result into a single optional:

let idx = fst.flatMap { find($0, 2) }
// idx will be of type Int? 
// and not Int?? unlike if `map` was used
Airspeed Velocity
  • 40,491
  • 8
  • 113
  • 118
  • 8
    Although you mention the nil sorting order, the construct "if i < 5 { }" can be dangerous in that its just so easy to decide to change the logic and write "if i >= 0 { }" instead on a future edit. Personally I try to always use "if let i = i where i < 5 { }" with optionals. – David H Jun 03 '15 at 16:25
  • A lot of this is mentioned, almost word for word, in "Advanced Swift" by Chris Eidhof https://www.objc.io/books/advanced-swift/ –  Jul 27 '17 at 18:34
  • 5
    It's almost as if one of the authors of that book wrote this as well. – Airspeed Velocity Aug 09 '17 at 10:01
  • The optional comparison was removed in Swift 3 - https://github.com/apple/swift-evolution/blob/master/proposals/0121-remove-optional-comparison-operators.md – Richard Groves Apr 30 '20 at 13:48
2

I think you should go back to the Swift programming book and learn what these things are for. ! is used when you are absolutely sure that the optional isn't nil. Since you declared that you are absolutely sure, it crashes if you're wrong. Which is entirely intentional. It is "unsafe and best avoided" in the sense that asserts in your code are "unsafe and best avoided". For example:

if someOptional != nil {
    someFunction(someOptional!)
}

The ! is absolutely safe. Unless there is a big blunder in your code, like writing by mistake (I hope you spot the bug)

if someOptional != nil {
    someFunction(SomeOptional!)
}

in which case your app may crash, you investigate why it crashes, and you fix the bug - which is exactly what the crash is there for. One goal in Swift is that obviously your app should work correctly, but since Swift cannot enforce this, it enforces that your app either works correctly or crashes if possible, so bugs get removed before the app ships.

gnasher729
  • 51,477
  • 5
  • 75
  • 98
  • 1
    This self-answer was written mostly in response to the constant appearance of the `if someOptional != nil { use someOptional }` in questions (and even in a couple of popular Swift tutorial books). I also disagree that using `!` is a good technique for when you want your program to crash on `nil`. You could be better off using `assert` with an explicit error message than they mystery-meat error you’ll get back from the `!`. – Airspeed Velocity Apr 18 '15 at 13:21
  • 2
    Possibly this isn’t the right one and I’m doing the wrong thing posting this, but there definitely need to be more canonical answers to optional questions, as “how can I do ” and similar come up _constantly_. – Airspeed Velocity Apr 18 '15 at 13:22
  • The second example will most likely lead to a compiler error, not to an actual app crash. – return true Aug 12 '15 at 10:43
  • This isn't "absolutely safe", because there's not guarantee you didn't accidentally `nil` out the variable somewhere in the beginning of your block. You should be using optional binding. – Alexander Jul 30 '18 at 17:53
0

You there is one way. It is called Optional Chaining. From documentation:

Optional chaining is a process for querying and calling properties, methods, and subscripts on an optional that might currently be nil. If the optional contains a value, the property, method, or subscript call succeeds; if the optional is nil, the property, method, or subscript call returns nil. Multiple queries can be chained together, and the entire chain fails gracefully if any link in the chain is nil.

Here is some example

class Person {
    var residence: Residence?
}

class Residence {
    var numberOfRooms = 1
}

let john = Person()

if let roomCount = john.residence?.numberOfRooms {
    println("John's residence has \(roomCount) room(s).")
} else {
    println("Unable to retrieve the number of rooms.")
}
// prints "Unable to retrieve the number of rooms."

You can check the full article here.

Sergey Pekar
  • 8,555
  • 7
  • 47
  • 54
0

We can use optional binding.

var x:Int?

if let y = x {
  // x was not nil, and its value is now stored in y
}
else {
  // x was nil
}
Keshav
  • 1,123
  • 1
  • 18
  • 36
0

After lot of thinking and researching i have came up with the easiest way to unwrap an optional :

  • Create a new Swift File and name it UnwrapOperator.swift

  • Paste the following code in the file :

    import Foundation
    import UIKit
    
    protocol OptionalType { init() }
    
    extension String: OptionalType {}
    extension Int: OptionalType {}
    extension Int64: OptionalType {}
    extension Float: OptionalType {}
    extension Double: OptionalType {}
    extension CGFloat: OptionalType {}
    extension Bool: OptionalType {}
    extension UIImage : OptionalType {}
    extension IndexPath : OptionalType {}
    extension NSNumber : OptionalType {}
    extension Date : OptionalType {}
    extension UIViewController : OptionalType {}
    
    postfix operator *?
    postfix func *?<T: OptionalType>( lhs: T?) -> T {
    
        guard let validLhs = lhs else { return T() }
        return validLhs
    }
    
    prefix operator /
    prefix func /<T: OptionalType>( rhs: T?) -> T {
    
        guard let validRhs = rhs else { return T() }
        return validRhs
    }
    
  • Now the above code has created 2 operator [One prefix and one postfix].

  • At the time of unwrapping you can use either of these operator before or after the optionals
  • The explanation is simple, the operators returns the constructor value if they get nil in variable else the contained value inside the variable.

  • Below is the example of usage :

    var a_optional : String? = "abc"
    var b_optional : Int? = 123
    
    // before the usage of Operators
    
    print(a_optional) --> Optional("abc")
    print(b_optional) --> Optional(123)
    
    // Prefix Operator Usage
    
    print(/a_optional) --> "abc"
    print(/b_optional) --> 123
    
    // Postfix Operator Usage
    
    print(a_optional*?) --> "abc"
    print(b_optional*?) --> 123
    
  • Below is the example when variable contains nil :

    var a_optional : String? = nil
    var b_optional : Int? = nil
    
    // before the usage of Operators
    
    print(a_optional) --> nil
    print(b_optional) --> nil
    
    // Prefix Operator Usage
    
    print(/a_optional) --> ""
    print(/b_optional) --> 0
    
    // Postfix Operator Usage
    
    print(a_optional*?) --> ""
    print(b_optional*?) --> 0
    
  • Now it is your choice which operator you use, both serve the same purpose.

Mr. Bean
  • 4,221
  • 1
  • 19
  • 34
  • Why are you assuming that an empty initialized value (`0`, `""`, `[]`, etc) is reasonable. The *entire point* of optionals is to force developers to consider this, and think what the sensible way to handle a non-value is. E.g. if I had a grade calculating app, that took the averages of all assignment grades, and no assignment grades were marked yet, should students be shown as having a 0% grade? No! – Alexander Jul 30 '18 at 17:52
  • @Alexander, you are right about the optionals usage in Swift, but this operator is for different usage, most of the crashes occur while forced down-casting or using Implicit Unwrapped optionals, to minimise these type of crashes the above mentioned operator can be used. Also developer has to be well aware of when to use the operator. The use of operator is to only provide Initialised value in place of nil, that's it. Thanks Alex :) – Mr. Bean Jul 31 '18 at 07:20
  • 1) Crashes can be preferable to allowing the propagation of nonsense data (the fact that unwrapping an optional causes a fatal error was programmed in, *intentionally*. It could have very well been the case that unwrapping an `Int?` just gave you what ever garbage was in that memory location. But instead, the Swift team intentionally implemented the check that throws a fatal error, to prevent such indeterminate states from arising. – Alexander Jul 31 '18 at 16:11
  • 2) The purpose of this operator is already satisfied by the existing nil coalescence operator (`??`). The key difference however, is that unlike your `/` and `*?` operators, it doesn't make any assumptions about what a correct "fall back value" is, on the programmer's behalf. It's up to them to decide for themselves. – Alexander Jul 31 '18 at 16:12