UIStoryboard on iOS 5: The Good, The Bad, and the 'This Plain Sucks'

iOS 5 has been a real treat, not just for the end-users, but also developers, as well.  The introduction of UIAppearance, CoreImage, ARC, and many other goodies has really amped up the awesomeness in developing rich applications at a much quicker pace.  One of the other interesting items is called UIStoryboard.  Storyboards offer us the ability to apply our Interface Builder skills and take it to the next level for developing cohesive applications through a WYSIWYG interface.  I developed my latest application, TF2 Recipes, exclusively in Storyboards in order to get a real feel of how they might be a benefit to the software development life-cycle.

First things first: storyboards are an excellent way to really visualize the flow of your application.  Being able to layout ahead of time how all your view controllers interact with each other is a really good thing because it saves you a ton of time writing those interactions down, creating mockups for them, or stumbling your way through as you develop your app.  Knowing where you are and where you are going is a must-have in any software project, but being able to do it in a single editor and have that translate directly into a functional app is definite plus.  Also, being able to spatially see where the focus of the activities in your application is helps you focus on making that part of the app the absolute best.

One of the things that really saved me time is that I had originally decided to do my app in a tab bar controller, but later decided to do a straight navigation controller app.  I didn't have to change a single line of code and in a few short minutes I had completely reconfigured my application as needed.

In my day job I see designers using storyboards in order to design the flow of the app before developers get their hands on it.  They didn't have to know any Objective-C code in order to prototype interactions and designs, which meant when a developer did get involved, many questions as to the behavior of the application had already been figured out.  A lot of mockups we get don't convey any animation or transition information, so a mocked up prototype using storyboards was incredibly useful.

But not all is rosy in the world of storyboards.  When I started adding a lot of complexity to my application, I started to notice something:  View controllers that were used a lot or had a lot of jump points to other parts of the app quickly became a tangled mess, not only in the visual editor, but especially in the prepareForSegue method in my code.  It can get quite hairy because one has to check the segue identifier before setting model object data to a destination view controller.  What makes this worse is that the identifier is an NSString, so things have to match character by character, otherwise your destination view controllers may not behave correctly.

One of the big bonuses of using storyboards comes in the form of prototype cells for tableviews.  This allows you to design a UITableViewCell instance inline with the rest of the table view, without having to create a separate XIB file to design it.  This really cuts down on the amount of files you end up having in your application and centrally manages all your UI cruft in one file.  You can perform automatic segues when a table view row is selected and transition onto the next view controller.  Sadly, though, accessory view actions cannot trigger a segue, in and of themselves.  You have to resort to code to do this, unfortunately, which kinda pours some cold water and the benefits of storyboards and table views.

One thing that I noticed from the WWDC video and a lot of tutorials that are out there on storyboards is that they all seem to focus on the iPhone.  After starting to work on the iPad implementation of TF2 Recipes, I can now see why.  Storyboards require a lot of screen real estate.  Even though you can zoom in and out of a storyboard, most work can only be done when you are zoomed in 100%.  This becomes quite dreadful to work with, even when you're on a large, high resolution screen that I use at home.  When you need to make segue connection between view controllers that are far apart from one another, it gets to be a real pain, real quick.  I'm glad I stuck with the iPhone first in my first adventures, or I would have been turned completely off doing the iPad.

On that note, there are some pretty serious bugs with iPad and storyboards.  The big one comes when you opt to use popovers.  Popovers are a very common UI element to use, but they behave differently than all other transition types in storyboard segues.  In other segues, the prepareForSegue method gets called first in the source view controller.  Sometime after that call, the view is loaded in your destination view controller.  This is important because you may do additional setup in your viewDidLoad, based upon the model objects that you would set on it.  However, with popovers, viewDidLoad gets called first, then the prepareForSegue method gets called in the source view controller.  The order of operation is crucial to how a view controller should setup and so messing it up in this manner is completely unacceptable.  You either have to switch 'all manual' for displaying that popover, or you have to delay your UI setup in a different UIViewController override, sometimes with undesired results.  Yes, this item is one of the 'This Plain Sucks' parts of storyboards.

In that same vein of popovers you have the ability, through Interface Builder, to set what are called the anchorRect or anchorView from which the popover should be displayed.  This is all incredibly useful if, and only if, the anchor view is actually in interface builder.  In my case I am using a custom UIView that gets programmatically added as a subview in my view controller.  There is no way to set the anchor rectangle or view programmatically at run time without using a private API. Lame-o.  Hopefully Apple don't reject my app for its necessitated use. (UPDATE: A year later, they did)  Making those properties hidden from the public API shows a great lack of foresight from the engineers that developed this.

One other debilitating flaw that I have discovered relates to the use of UISearchViewController (this happens on both iPhone and iPad).  I have been able to reproduce a problem where if you 1) have a search view controller that was added in storyboards, 2) you go to a new view controller, like through a navigation push, 3) the view gets unloaded because of a low memory situation, and 4) you return to the view controller, like through a pop, then 5) your app will crash because the underpinning code from Apple sends a message to the deallocated instance.  This error does not occur when using plain XIBs, just in storyboards.  The work around is to create the search view controller programmatically in your viewDidLoad.  It's a crummy workaround, but it is one nonetheless.

To wrap up, storyboards are wonderful for rapidly getting an application up and running.  I've seen great success in even using them as a prototype to show stakeholders how the app will function once developers get their hands on it.  But there is a hidden cost.  Storyboards are no <insert cliche here> and for complex applications may be more trouble than they are worth.  I really enjoyed using them in my iPhone application, but I think they were a bit much for iPad.  Too much space, Interface Builder was very buggy, and there are still a lot of kinks to work out.  Knowing ahead of time some of the pitfalls that you may face, I really encourage you to use storyboards as much as possible.  You don't have to use a single storyboard per app, but can instead create multiple storyboards per application flow.  You may find that this approach offers great flexibility and allow you to take advantage of the benefits of storyboards without having to run through all the mud-patches with it.

Posted on Jan 7
Written by Wayne Hartman