Unwrap Swift optional value in Switch case
Table of Contents
When you want to unwrap an optional value in Swift, you probably use if let
or guard let
syntax.
let name: String? = "Sarunw"
if let name = name {
print("Hello, \(name)!")
} else {
print("Hello, World!")
}
But you might not be aware that you can also do this in a switch
statement.
Unwrap optional value the wrong way
Unwrap optional value with switch case
is a bit tricky if you aren't familiar with the language.
First, let's try to unwrap it the wrong way.
let name: String? = "Sarunw"
switch name {
case let unwrappedName:
print("Hello, \(unwrappedName)!")
default:
print("Hello, World!")
}
If you try to do it like this, you will get two warnings.
- The first one is because our
unwrappedName
variable that we expected it to be unwrapped is still an optional value. - The second warning one telling you that the
default
case wouldn't be reached.
As you can see, we can't use case let
[1] to unwrap an optional value in switch case
. That would just bind the same optional value to a new variable[1:1].
Since the first case just takes any value and reassigns it to a new variable, there is no more case to handle. And that is a reason why the default
case won't be reached.
You can easily support sarunw.com by checking out this sponsor.
Translate your app In 1 click: Simplifies app localization and helps you reach more users.
Optional Binding using a switch statement
You have to know one fact to unwrap an optional value using a switch
statement. That is, an optional is just an enum.
Optional Enum
Optional
is an enumeration with two cases.
none
represents an absence of a value (nil
).
some(Wrapped)
represents a presence of a value stored as an associated value.
enum Optional<Wrapped> : ExpressibleByNilLiteral {
case none
case some(Wrapped)
}
Since it is an enum with an associated value, we can get an unwrapped optional value by reading the associated value from the .some
case, the same way we do with a normal enum.
let name: String? = "Sarunw"
switch name {
case .none:
print("Hello, World!")
case .some(let unwrappedName):
print("Hello, \(unwrappedName)!")
}
Optional Pattern
There is also a special pattern for direct matches against a value wrapped in a .some(Wrapped)
called Optional Pattern.
You can use an Optional pattern by putting a question mark (?
) right behind a variable name.
Optional patterns are syntactic sugar for Optional enumeration case patterns. So, the following are equivalent:
let name: String? = "Sarunw"
switch name {
case .none:
print("Hello, World!")
case .some(let unwrappedName):
print("Hello, \(unwrappedName)!")
}
switch name {
case .none:
print("Hello, World!")
// Optional Pattern
case let unwrappedName?:
print("Hello, \(unwrappedName)!")
}
case .some(let unwrappedName)
is equivalent to case let unwrappedName?
.
You can easily support sarunw.com by checking out this sponsor.
Translate your app In 1 click: Simplifies app localization and helps you reach more users.
Conclusion
Unwrap optional values using a switch
statement might seem overcomplicated for simple cases that I show in this article. But you would find a place for it in more complex cases.
Here is an example of an optional as an associated value of another enum.
let result: Result<String?, Error> = .success("Response")
switch result {
case .success(let str):
// 1
if let str = str {
print("Success: \(String(str))")
} else {
print("Success with no Data")
}
case .failure(let error):
print("Failure: \(error.localizedDescription)")
}
switch result {
// 2
case .success(let str?):
print("Success: \(String(str))")
// 3
case .success(.none):
print("Success with no Data")
case .failure(let error):
print("Failure: \(error.localizedDescription)")
}
- In the first case, 1, we unwrap an optional associated value using
if let
. - In the second case, we use what we learn and split
.success
into two cases. One for a success case with value 2, another one without the value 3.
Another example where this might be useful is when we have to control the flow based on more than one optional value.
In this example, I try to print a proper message based on two optional values, first name and last name.
let firstName: String? = "John"
let lastName: String? = nil
if let firstName = firstName,
let lastName = lastName {
print("\(firstName) \(lastName)")
} else if let firstName = firstName {
print("Only \(firstName)")
} else if let lastName = lastName {
print("Only \(lastName)")
} else {
print("No name")
}
switch (firstName, lastName) {
case let (firstName?, lastName?):
print("\(firstName) \(lastName)")
case let (firstName?, .none):
print("Only \(firstName)")
case let (.none, lastName?):
print("Only \(lastName)")
case (.none, .none):
print("No name")
}
There is nothing wrong with if else
, but I usually find this kind of comparing easier to understand on a switch
statement.
The thing we learned in this article is just a tool. You have to judge for yourself when to use it. There is no right or wrong.
A value-binding pattern binds matched values to variable or constant names. https://docs.swift.org/swift-book/ReferenceManual/Patterns.html#ID422. ↩︎ ↩︎
Read more article about Swift or see all available topic
Enjoy the read?
If you enjoy this article, you can subscribe to the weekly newsletter.
Every Friday, you'll get a quick recap of all articles and tips posted on this site. No strings attached. Unsubscribe anytime.
Feel free to follow me on Twitter and ask your questions related to this post. Thanks for reading and see you next time.
If you enjoy my writing, please check out my Patreon https://www.patreon.com/sarunw and become my supporter. Sharing the article is also greatly appreciated.
Become a patron Buy me a coffee Tweet ShareHow to change Background Color of Button in SwiftUI
Learn how to change the background color of a SwiftUI Button.
Enable and Disable SwiftUI List rows reordering on a specific row
The onMove modifier enables item reordering on every row. Let's learn how to disable this on particular rows.