Hey! Who remembers that comic book manger app I was writing a few months ago?
Not me! Actually I didn’t forget about Book Binder–I just smacked into my own limitations. I had to take a break and do a bunch of reading, learning, and experimenting.
And now I’m back. Look at a what I did…
My problem with Book Binder was creating a well designed navigation view hierarchy and wiring it all together. And so I dug in and figured it out (with a lot of help from Ray Wenderlich and Stack Overviewflow. Thanks Ray, Joel, and Jeff!)
You’ll find the new codebase here: Comic Keeper
But let’s talk about view controllers, show segues, and unwind segues for a few minutes. In the image above I have tab bar controller as my root with three tabs. The 2nd and 3rd tab are trivial. It’s the first tab that is entertaining! I have a deep navigation view hierarchy with 8 view controllers linked by 15 show segues, 6 unwind segues, and 4 relationship segues.
What I like about storyboards and segues is Xcode’s visualization. It’s a nice document of how an iOS app works from main screen to deeply nested supporting screens. Once you learn the knack of it of it, control-dragging between view controllers to create segues is easy. Unfortunately creating a segue is the also the least part of the effort in navigating from one iOS view to another.
Given the number of screens and bi-directional connections I have in this foolish little app, navigation management consumes too much of my coding. And these connections are fragile in spite of all the effort UIKit puts into keeping connections abstract, loose, and reusable.
Let’s take a quick look at what have to do each time I want to connect a field from the EditComicBookViewController to one of the item picker view controllers:
- Update EditComicBookViewController:prepare(for:sender:) method with a case for the new show segue. I need to know the name of the segue, the type of the destination view controller, and the source of the data I want to transfer into the destination. I have a giant switch statement to manage the transactions for each show segue. I did create a protocol, StandardPicker, to reduce the amount of boilerplate code generated by each show segue.
- Update EditComicBookViewController unwind segue for each particular type of item picker I’m using. I have four reusable item pickers (edit, list, dial, and date) and four unwind segues (addItemDidEditItem, listPickerDidPickItem, dialPickerDidPickItem, datePickerDidPickDate). A function corresponding to each unwind segue is better than having one method for all show segues. But I still have conditionals that choose the EditComicBookViewController field to update based on the title I gave to the picker. This view controller/segue pattern is not really set up for reuse.
- I have to create a show segue from the source view controller to the destination and an unwind segue from the destination back to source. This is all assuming these views are embedded in the same UINavigationViewController. Each segue needs it’s own unique ID and its pretty easy to confuse the spelling of that ID in the supporting code.
How could navigation be better supported in Xcode and UIKit?
First, I’d like to bundle together the show and unwind segues with the IDs and the data in a single object. I’m sure this exists already, as it’s pretty obvious, but Apple isn’t providing an integration for storyboards. Ideally, I would control-drag to connect two view controllers and Xcode would pop-up a new file dialog box to create a subclass of StoryboardSegue and populate it with my data. The IDs should be auto-generated and auto-managed by Xcode. That way I can’t misspell them.
Second, I’d like the buttons in the navigation bar to each trigger separate but standard events:
Right now you have to build your own mechanism to track the direction of navigation in viewWillDisappear(). In the navigation hierarchy of every app there is semantic meaning to moving forward and backward through the hierarchy similar to but potentially different from the show/unwind segue semantics. Tapping the back button might mean oops! Get me out of here while tapping a done button might mean I’ve made my changes, commit them and get me out of here!
Third, I’d like Xcode’s assistant editor view to show the code for a segue when I click on a segue. The navigation outline and storyboard visualization is a great way to hop from view controller to view controller. While Xcode knows about the objects that populate controllers, it doesn’t navigate you to any of them. Clicking on a connection in the connections inspector should load the code for that connection in the assistant editor. Xcode does highlight the object in the storyboard but I want more.
As my apps get more ambitious and sophisticated I’m probably going to abandon storyboards like the Jedi Master iOS developers I know. That’s sad because I feel I’ve finally figured out how to wire-up a storyboard-based view controller hierarchy and I’m already leveling out of that knowledge as the Jedi Masters smile smugly.