Update: with Xcode 12, we can write if let bindings without problems. This code is now valid:
if let address = library.address {
Text(address)
}
I'll leave the post up for historical context.
Recently I was building an app that lists public libraries in my home city. In early stages, the main view was just a list view that displays the library name and address. Something like this:
As you can see, some libraries don't have an address, because of some unrelated reasons. And if the address isn't present, the name should be vertically centred in the row.
A library not having an address is translated into my data model as an optional String. Here's a simplified version of my Library model:
struct Library {
let id: String
let name: String
let address: String?
}
Initial approach
If a library doesn't have an address, I won't render a Text component for it, simple as that. And the easiest way for me to do that was using an if let binding:
VStack {
Text(library.name)
if let address = library.address {
Text(address)
}
}
As it turns out, SwiftUI doesn't like this. The compiler tells us that Closure containing control flow statement cannot be used with function builder 'ViewBuilder'. I beg your pardon?
How else am I supposed to conditionally render views in my app if "control flow statement cannot be used" to build it? After a moment of panic, I tested using a normal if:
VStack {
Text(library.name)
if library.address != nil {
Text(library.address!)
}
}
And surprisingly that worked... wtf. Needless to say, I wasn't very exited with that solution, since it requires force unwrapping an optional value. I knew that there was another way.
Current solution
One of the key features of SwiftUI is that if we add a nil component to our view, it won't show up, it's just ignored. So, what's the easiest way to convert a conditional string into a conditional Text? That's right, using map.
Here we map over the possibly nil address, without needing to force unwrap it, as the closure will only be executed if there was a value in the first place. This, however, seems like a hack. But hey, It works.
VStack {
Text(library.name)
library.address.map { address in
Text(address)
}
}
Let's wait and see
As I was reading some discussions about this issue, I found out that SwiftUI builds views using a struct named ViewBuilder — remember the error I was getting before? If we peek its definition (cmd + shift + o in XCode to go to any class definition) we can clearly see that it supports if statements, but nothing more.
SwiftUI is not event a year old, and we know Apple only introduces big features once a year. So here's hoping that when the next version of SwiftUI shows up, they add if let support.

Top comments (3)
if let– is from another paradigm.The sense of SwiftUI goes to declarative approach, but not into imperative, which is classic.
If you're saying that
if letisn't supported in SwiftUI because it's not declarative, then why is the normalifsupported? It's even used in the official documentation. To me, both share the same level of "imperativeness", but theifis not as type-safe in this case!It's clear that SwiftUI it's inspired by other declarative frameworks like React.js or Vue.js, and in those is idiomatic to check if values are present to conditionally render a view. Something like this:
Here, since we are checking that
library.addresshas a value, TypeScript smart casts it from astring?to a normalstring. It's the TS equivalent of anif letbinding.I wouldn't use React as example of correctness, as it's also not a mature technology.
In case of SwiftUI, I think, they will propose appropriate usage for cases that you aware of.