Composable Navigation: Correctness

Episode #229 • Apr 3, 2023 • Subscriber-Only

We now support many different forms of navigation in the Composable Architecture, but if used naively, they open us up to invalid states, like being navigated to several screens at a time. We’ll correct this with the help of Swift’s enums.

Previous episode
Composable Navigation: Correctness
Next episode
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

Stephen

We now have a pretty incredible and comprehensive suite of navigation tools for the Composable Architecture. We can handle alerts, confirmation dialogs, sheets, popovers, covers, navigation links, and even a new iOS 16 style of navigation destinations. And it doesn’t matter which form of navigation you are trying to implement, the steps to do it are all basically the same. You do a bit of domain modeling, you integrate the parent and child features together using the ifLet reducer operator, and then you integrate the view by calling the corresponding SwiftUI view modifier.

There is of course a big, gaping hole in our navigation tools, and that is the new iOS 16 NavigationStack API that takes a binding. This style of navigation is extremely powerful, though sometimes difficult to handle correctly, and we will have a lot to say about that soon, but there is something more important to address first.

Brandon

While what we have accomplished so far is pretty impressive, after all we have unified 6 different forms of navigation into essentially a single API, we are still modeling our domain in a less than ideal way. Our inventory feature is using 4 pieces of optional state to represent all the different places you can navigate to, and that allows for a lot of non-sensical states which leaks uncertainty into every corner of our codebase.

For example, it’s technically possible for the addItem and duplicateItem and editItem all be non-nil at the same time. What does that even mean? A sheet, popover, and drill-down would all activated at the same time? And beyond that weirdness we can also never be sure that we know exactly what screen is being displayed at any time. We have to check all 4 optionals to see if something is presented and if 2 or more things are non-nil we just have to guess at what is actually being displayed.

By using 4 optionals we technically have “2 to the 4th” possible states of things being nil or non-nil, which is 16 possibilities. Only 5 of those are valid: either they are all nil or exactly one is non-nil. That leads us to believe that a single enum is a much better tool for modeling this domain than a bunch of optionals, and that’s a lesson we learned when discussing vanilla SwiftUI navigation, as well as modern SwiftUI.

We put in a lot of effort to build up navigation tools in vanilla SwiftUI that allowed us to model all destinations as a single enum, and then derive bindings to each case of the enum in order to drive navigation. We need to do the same for the navigation tools we have just built for the Composable Architecture, so let’s see how we can accomplish that.

Enum navigation


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