🎉 Black Friday Sale! Save 30% when you subscribe today.

SwiftUI Navigation: Links, Part 3

Episode #167 • Nov 8, 2021 • Subscriber-Only

Over the past weeks we have come up with some seriously powerful tools for SwiftUI navigation that have allowed us to more precisely and correctly model our app’s domain, so let’s exercise them a bit more by adding more behavior and deeper navigation to our application.

Collection
Navigation
SwiftUI Navigation: Links, Part 3
Locked

Unlock This Episode

Our Free plan includes 1 subscriber-only episode of your choice, plus weekly updates from our newsletter.

Sign in with GitHub

Introduction

So, this is all looking really promising. We have an incredible amount of power in deep linking and testing in our application. When we first started discussing navigation links earlier in this episode we mentioned that they are the most prototypical form of navigation, but also at the same time the most “complicated.”

However, we just introduced a pretty complex navigation link for editing an item, and even showed how we could gate the navigation based on asynchronous effects. This is some of the most complicated navigation you can do in an iOS application, and not only did we accomplish it pretty quickly, but we also got deep linking for free along the way. To contrast with modal sheets and popovers, it took us three very long episodes to develop the techniques that allowed us to model them in state and support deep linking.

Perhaps this form of navigation isn’t so complicated after all?

Well, it definitely is, but it’s come much easier to us thanks to all of the tools we built in previous episodes. The only reason we are able to model our navigation routes as a simple enum and implement a NavigationLink initializer that transforms binding of optionals into bindings of honest values is thanks to all the binding transformation helpers we have defined in past episodes.

So, we’re starting to see that by putting in a little bit of upfront work to try to put structs and enums on the same footing when it comes to binding transformational operators, we unlock powerful tools that help make navigation in SwiftUI a breeze. Just as dynamic member lookup allows us to slice of a binding for a piece of sub-state and hand it off to a child component, the .case transformation allows us to slice off a binding for a particular case of an enum and hand it off to a child component. And when you combine that with navigation tools such as sheets, popovers, and links, you instantly unlock the ability to drive navigation off of state.

But let’s push things even further. Right now the ItemView has no behavior. It’s decently complex, especially since we are transforming the item status binding into bindings for each case of the status enum. But even so, there’s no real behavior in the screen. We aren’t executing any asynchronous work or side effects. The SwiftUI view is just reading from bindings and writing to bindings.

This has worked well for us so far, but as soon as we want to introduce some behavior to the view, and do so in a testable way and in a way that allows for deep linking, we can no longer get away with using simple bindings. We must use an observable object. We’ve already got two observable object view models in this project: one for the inventory list feature and one for the row of the list.

We’re going to introduce yet another view model, this time for the item view. In order to justify this new view model we are going to add some complex behavior to the screen. We are going to add some validation logic to the form, and we’re going to make the color picker more robust by having it load additional colors from an asynchronous effect.

Let’s start by trying to implement these features without a view model and show where things go wrong.

Item validation and a custom color picker


References

Downloads

Get started with our free plan

Our free plan includes 1 subscriber-only episode of your choice, access to 64 free episodes with transcripts and code samples, and weekly updates from our newsletter.

View plans and pricing