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.