Optionals in SwiftUI
Apple’s new UI framework is missing an “if let”, so now what?
This article focuses on a specific pain-point in SwiftUI and assumes you’re familiar with with the basics. Check out the tutorials if you’re not, they’re great!
Apple has just announced the next big thing in iOS and Mac development at WWDC: SwiftUI. It’s a new UI framework and it seems to be fulfilling the dream: Use Swift and a visual interface editor to design and build interfaces, and do this in a declarative manner. This means you can describe how the interface is supposed to work under certain circumstances and you don’t need to manually update your UI to correspond with the changes in the data. Along with Combine, Apple’s new RX-framework (check out this post as well if you’re interested), your interfaces will be updated automatically.
Working with optionals
One of the things you’ll encounter a lot when building UIs is optional values. You get data from an API and need to render some UI accordingly, but you can’t assume all data is available. Taking a Twitter app as an example, you’d guess you can do something like this:
When a tweet has an image, we want to render it. If it doesn’t, we want to render no image. Working with optionals in Swift is a breeze with the
if let construction. And this is all just Swift, right? Wrong. The above example will give you this error:
// Closure containing control flow statement cannot be used with function builder ‘ViewBuilder’
Welcome to the world of Function Builders! This is a new feature in Swift, you can read its proposal if you’re interested. Function builders provide us with a way of collecting the result of functions into an output. SwiftUI uses this to get the output of your components and turn it into a UI (it’s called the
ViewBuilder). All SwiftUI views (like
List and so on) are
ViewBuilder's. Because of this, the code you type inside of a view isn’t “just Swift”, it’s “Swift that is supported from within the function builders that Apple has provided in this version of the framework”.
One thing we can do is list multiple components:
Another language feature we can use are if/else statements, as long as we wrap it inside of a single view (because
some View prevents us from using different top-level components).
As far as we can figure out at the moment, that’s about it. No
if let, no
switch, so… what do we do? We could wait for Apple to implement these kind of things, but that’s no fun. Luckily there’s a workaround: We could create a view for it! Similarly to the built-in
ForEach, we can create an
With this we can fix our earlier example, like so:
Of course it would be nicer if you don’t need to think about these kind of things, but we expect it’s only a matter of time before Apple implements more fundamentals. Just don’t let it stop you from playing around with this shiny new stuff.
Update: Use map instead!
After fiddling around with this a little bit more, we found another way of doing this:
Mapping on an optional results in an optional
Image when the value turns out to be
nil, so this actually works like a charm! No need for a separate view to handle the
if let. If you want to do an
if let else with the same kind of view, you can do so as well:
If you want to fall back to a different kind of view, you need a tiny bit of manual
ViewBuilder code, but you can do that inline as well:
Check out our other WWDC19 blog posts on https://medium.com/q42-engineering/wwdc19.