On if let bindings in SwiftUI
Tags: swift, swiftui, ios, macos
Published: 2020-04-11 16:59:43

**Update**: with Xcode 12, we can write `if let` bindings without problems. This code is now valid:

```swift
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:

![Screenshot showing a quick prototype for my app](https://dev-to-uploads.s3.amazonaws.com/i/mqmwhmoa1k6nt51oo1m9.png)
<figcaption>Quick prototype of my app</figcaption>

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:

```swift
struct Library {
    let id: String
    let name: String
    let address: String?
}
```
<figcaption>Neat, eh?</figcaption>

## 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:

```swift
VStack {
    Text(library.name)
    if let address = library.address {
        Text(address)
    }
}
```
<figcaption>This WON'T compile!</figcaption>

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`:

```swift
VStack {
    Text(library.name)
    if library.address != nil {
        Text(library.address!)
    }
}
```
<figcaption>Force unwrapping make kittens cry</figcaption>

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.

```swift
VStack {
    Text(library.name)
    library.address.map { address in
        Text(address)
    }
}
```
<figcaption>Heh, mapping an optional... I can still hear my CS professor talking about monads.</figcaption>

## 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`][1] &mdash; 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.

[1]: https://jasonzurita.com/swiftui-if-statement/