Any time you use an optional value, you will have to unwrap it in one way or another. Even if you know for certain that it has a valid value because of the way that you have coded it.
So, if you consider this code...
struct ContentView: View {
let myNumber: Int? = 1
var body: some View {
Text("\(myNumber)")
}
}
It won't work. Even though we know that we set myNumber
equal to 1, and it is a constant (let
), so it can not be changed. Swift still tries to be careful because we have declared it as an Int?
(optional Int
).
So, we have a few options...
We can force unwrap the value with !
struct ContentView: View {
let myNumber: Int? = 1
var body: some View {
Text("\(myNumber!)")
}
}
But if myNumber
actually contains nil
in this case, then the program will crash.
We can use if let
to unwrap the value
struct ContentView: View {
let myNumber: Int? = 1
var body: some View {
if let myNumber {
Text("\(myNumber)")
}
//possible additional code here
}
}
In this case, if myNumber
contains nil
then the entire if let myNumber { ... }
block of code is just skipped. So no Text
view would be shown in ContentView
and nothing else would be done.
(If we included any additional code after the end of the if
closure it would still be run.)
We can use guard let
to unwrap the value
struct ContentView: View {
let myNumber: Int? = nil
var body: some View {
guard let myNumber else { return Text("No value found") }
return Text("\(myNumber)")
}
}
In this case, if myNumber
contains nil
then a Text view containing "No value found" would be shown instead of the value of myNumber
. We would immediately return from the body
closure as soon as the guard
condition is false. So, any code after the guard
line will be completely ignored.
(The else
closure and the code that comes after it must both return some View
to keep the body
property satisfied.)
Try chaging the line
let myNumber: Int? = 1
to
let myNumber: Int? = nil
in each of the examples above, and run the code to see what different results you get.
But yes, you can use if let myNumber { } else { }
as well, and it could work almost the same way as guard let myNumber
would. But notice that the if let
option does not use the return
keyword.
struct ContentView: View {
let myNumber: Int? = nil
var body: some View {
if let myNumber {
Text("\(myNumber)")
} else {
Text("No value found")
}
//possible additional code here
}
}
So, in this case, any code included after the if/else
closures would still be run, but any code included after the guard
would not.
Note: We used to have to write let myNumber = myNumber
when unwrapping optionals, but now we can just write let myNumber