64

How do you unwrap a string that is returned as:

(Optional(Optional "blue"))

var cityName = String()

if let cityAnno = annotation as MGLAnnotation! {
    cityName = String(stringInterpolationSegment: cityAnno.title!)
}

cityLabelName.text = ("\(cityName), \(county)")

cityLabelName prints out as (Optional "New York")

Claus Jørgensen
  • 25,882
  • 9
  • 87
  • 150
Max Phillips
  • 6,991
  • 9
  • 44
  • 71

7 Answers7

174

Given a double optional such as this doubly wrapped String:

let a: String?? = "hello"
print(a as Any) // "Optional(Optional("hello"))\n"

@Leo, showed that you could use optional binding twice:

if let temp = a, let value = temp {
    print(value) // "hello\n"
}

or force unwrap twice:

print(value!!)  // don't do this - you're just asking for a crash

Here are 5 more methods you can use to safely unwrap a double optional:

Method 1:

You can also use pattern matching:

if case let value?? = a {
    print(value) // "hello\n"
}

As @netigger noted in their answer, this can also be written as:

if case .some(.some(let value)) = a {
    print(value) // "hello\n"
}

which while less concise might be a bit easier to read.


Method 2:

Alternatively, you can use the nil coalescing operator ?? twice:

print((a ?? "") ?? "")  // "hello\n"

Note: Unlike the other methods presented here, this will always produce a value. "" (empty String) is used if either of the optionals is nil.


Method 3:

Or you can use the nil coalescing operator ?? with optional binding:

if let value = a ?? nil {
    print(value)  // "hello\n"
}

How does this work?

With a doubly wrapped optional, the value held by the variable could be one of 3 things: Optional(Optional("some string")), Optional(nil) if the inner optional is nil, or nil if the outer optional is nil. So a ?? nil unwraps the outer optional. If the outer optional is nil, then ?? replaces it with the default value of nil. If a is Optional(nil), then ?? will unwrap the outer optional leaving nil. At this point you will have a String? that is nil if either the inner or outer optional is nil. If there is a String inside, you get Optional("some string").

Finally, the optional binding (if let) unwraps Optional("some string") to get "some string" or the optional binding fails if either of the optionals is nil and skips the block.


Method 4:

Also, you can use flatMap with optional binding:

if let value = a.flatMap({ $0 }) {
    print(value)  // "hello\n"
}

Method 5:

Conditionally cast the value to the type. Surprisingly, this will remove all levels of optionals:

let a: String?? = "hello"
let b: String??????? = "bye"

if let value = a as? String {
    print(value)  // "hello\n"
}

print(b as Any)  // "Optional(Optional(Optional(Optional(Optional(Optional(Optional("bye")))))))\n"

if let value = b as? String {
    print(value)  // "bye\n"
}
vacawama
  • 150,663
  • 30
  • 266
  • 294
  • 36
    The `?? nil` is brilliant! – fpg1503 Aug 23 '16 at 18:47
  • 3
    This is the best answer, especially Method 3. – Rafael Nobre Oct 18 '16 at 01:41
  • I like method 1 although the pattern matching syntax takes some getting used to. Why and how does method 3 work? – Raginmari Jan 29 '18 at 11:06
  • 1
    @Raginmari, with a doubly wrapped optional, the value held by the variable could be one of 3 things: `Optional(Optional("some string"))`, `Optional(nil)` if the inner optional is `nil`, or `nil` if the outer optional is `nil`. So `a ?? nil` unwraps the outer optional. If the outer optional is `nil`, then ?? replaces it with the default value of `nil`. If `a` is `Optional(nil)`, then ?? will unwrap the outer optional leaving `nil`. At this point, you get `nil` if either the inner or outer optional is `nil`. If there is a string inside, you get `Optional("some string")`. – vacawama Jan 29 '18 at 14:51
  • 1
    Finally, the optional binding unwraps `Optional("some string")` to get `"some string"` or it fails if either of the optionals was `nil`. – vacawama Jan 29 '18 at 14:51
  • Method #1 has a really weird syntax! I've used it for enums but never like this. I also found Method #5 very interesting. Infact these 2 are the most concise and neat when it comes to a multi-optional variable but I highly doubt I will ever come across such a scenario :D – staticVoidMan Apr 30 '18 at 23:27
  • 2
    Methods 1 and 3 are the best code snippets I've read on the case. Thank you for such a great post! – Lucas P. Jun 05 '18 at 11:49
  • I suggest a language update that would use `iff let value = a`. It would be a nice shortcut to unwrap both optionals. – Victor Engel Feb 22 '19 at 14:51
  • I also note that these methods are not functionally equivalent. Some will execute the code producing a nil. Others will skip the code. – Victor Engel Feb 22 '19 at 15:12
  • All if the `if let` methods above perform optional binding and will skip the block if either optional is `nil`. Method 2 will produce `""` (empty String) if either optional is `nil`. Force unwrapping twice will crash if either optional is `nil`. – vacawama Feb 22 '19 at 15:25
  • I really like method 3. (voted) It took me a minute to realize that it's actaually intepreted as `if let value = (a ?? nil)` – Duncan C Sep 29 '20 at 19:36
  • 1
    Nice! I particularly like the conditional cast, since, like you said, it removes all levels of optionals! – Merricat Oct 20 '20 at 23:43
6

Try

var a:String?? = "1"
print((a))
if let b = a,c = b{
    print(c)
}

Screenshot of playground

enter image description here

Also you can force unwrap,but it it is not secure

let d = a!!
Leo
  • 24,596
  • 11
  • 71
  • 92
4

I must say the accepted answer is very good, and I pefer method 1 from from that answer. However I'd like to use different syntax, making it a little more readable:

if case .some(.some(let value)) = a {
    print(value) // "hello\n"
}
netdigger
  • 3,659
  • 3
  • 26
  • 49
1

I've made a reduce() method on Optional to transform an Optional(Optional(U)) into an Optional(U) (like flatten() in Scala):

extension Optional {
    /// - Returns: Given an Optional(Optional(U)) returns an Optional(U)
    func reduce<U>() -> U? {
        switch self {
        case let unwrapped?:
            return unwrapped as? U
        default:
            return .none
        }
    }
}

To use it:

String example:

// By using reduce() you directly got a standard optional you can unwrap in the standard way (see answer of @vacawama above).
let aString: String? = Optional(Optional("Hello")).reduce()

let unwrapped = aString ?? "Default"

Int example:

// By using reduce() you directly got a standard optional you can unwrap in the standard way (see answer of @vacawama above).
let anInt: Int? = Optional(Optional(5)).reduce()

let unwrapped = anInt ?? 10

I mainly use it when I want to call a method which can throw an exception but for which in the current context I don't want to catch it. An example is reading a user property in the keychain:

let username: String = (try? keychain.get("username")).reduce() ?? "unknown"
Artheyn
  • 1,042
  • 10
  • 7
0

Replace cast to optional if let cityAnno = annotation as MGLAnnotation! with an optional cast if let cityAnno = annotation as? MGLAnnotation

If you ended up having a double optional type, you probably made a mistake before that.

For example:

  1. Casted to optional type, e.g. value as? Value? instead of value as? Value
  2. Used map and returned an optional instead of using flatMap
  3. Created a Dictionary with optional values [Key: Value?] so subscript returns Value??
  4. Created an array of optionals
  5. Mapped an array using map instead of compactMap and then called a method that normally returns optional, e.g., first except now it's double optional

In 99% of cases, all of the above can be and should be avoided. In cases when you really need it, you probably already know all of the above.

0

For Swift 5.7, you can use

let value: String?? = "hello"
if let value, let value {
    print(value) // "hello"
}
-1

This is more of an important comment.

Think of a double optional as such:

indirect enum S {
  case value(s: S?)
  case none
}

While a normal optional is like this:

enum S {
  case value(s: S)
  case none
}

understanding why indirect is used in the first example is unimportant to scope of the question asked. It just doesn't compile without it! In the first example I was just trying to show that its internal type is also an optional type

mfaani
  • 33,269
  • 19
  • 164
  • 293