Storyboarding is one of the most exciting new features about the iOS 5 SDK. Take a look at the wealth of functionality offered by Storyboards in today's iOS 5 SDK tutorial!
The iOS 5 SDK comes with a lot of new API's to play with. iCloud is a great new interface for developers to use to make their application create the most seamless user experience possible. ARC presents a very fundamental shift in memory management throughout your applications. But arguably the most disruptive addition to the iOS 5 developer tool belt is Storyboarding. Storyboarding is big. It will change the way you write a majority of your interface code and also presents the potential to effect your development workflow as a whole throughout a team. Is storyboarding the right API for your next app? Should you upgrade your existing apps to use it? Let's dive into this new API some more and see what it has to offer.
Mile High Overview
Essentially, Storyboards are a new type of container available in Xcode to hold collections of NIB/XIB's. As a result, you may never need to use just an independent *.XIB file again (don't panic - they will still behave exactly as they have previously if you need to keep using them for now). Not only will a Storyboard file hold a collection of NIBs, but it will also allow you to visually control how those views will segue between each other. This means the entire flow of your app's interface can be modeled and visualized through your single storyboard file. Generally, interface flow requires the ability to get instances of controllers you want to flow to, send data to those instances, and then actually display those instances with some type of segue or transition. This is all very simple to do using Storyboarding, and using Storyboards instead of XIB files will let you cut a lot of code out of your projects. But Storyboarding doesn't stop there. Storyboarding can also enable you to create table view cells and table view controllers with simplicity. Let's take a look at how UIStoryboarding specifically addresses each of these use cases.
Compatibility Considerations
An important consideration before deciding to use Storyboarding is versioning. A project built with Storyboarding will be compatible with iOS 5 and greater. While you could build an app with Storyboarding and create proper checks to use other iOS 4 or prior friendly XIB's at certain places, that would be a lot of extra work for little pay off. If you are going to need to support releases prior to iOS 5, you should likely use the standard view controller and XIB method of UI development.
Sample Project Code
There is a sample project to accompany this article. You can grab it over at GitHub.
Scene Creation
All of UIStoryboards abilities are interconnected in one way or another, so deciding on a logical entry point to describe the objects is difficult. We will begin by looking at the new Storyboard layout interface and work forward from there. Below you will see an example of a UIStoryboard editor window within Xcode 4.2:
Here you can clearly see that I have 6 different view controllers presented throughout the flow of the application. For consistency with the official Apple nomenclature, we will refer to each of the storyboard sections as a "scene". Some scenes will have *.h and *.m view controller files, and some are completely configured in Interface Builder. In the demo project, I present an initial scene that leads to 5 distinctly different scenes. I only have 3 explicitly defined UIViewController subclasses to cover all 6 scenes. This whole flow of moving scenes on and off screen can be composed from this Storyboard layout view. The picture above shows the zoomed out story board view. Here you can not move specific UIKit elements around on the views, but rather you are meant to organize the high level flow of your scenes. Once you have finished that, you can zoom in and begin to specify the details of each scene.
Table View Controllers Rebooted
View Controllers, especially table view controllers, can now be explicitly defined exclusively through Storyboarding. From now on, if you view controller or table view controller contains only static content you can choose to implement the entire thing through the Storyboard editor. Interface Builder's inspector panes have been updated with everything you need to define a static table view and design your table view cells. Below you can see a zoomed up image of the options to configure these static tables and cells through Interface Builder.
Table View's now can be specified as static. This leads to an incredible savings of time if you have faced programmatically creating a complex table view of static data. Here is a screen shot of my static table view in my sample application. Any developer with extensive table view development experience can identify with how long this would have previously taken, but with Storyboarding it took me all of a few minutes.
In order to facilitate this, all of the data source information we are so familiar with providing for table views is now visualized through the object hierarchy view in Interface Builder. This will represent all of your tables sections, cells and so on. Keeping an eye on this will let you understand how the WYSIWYG actions you are performing translate into the more traditional data inputs for table views.
So, as you can see, there is tons of new stuff here! Many applications have non dynamic table views that have previously been implemented with distinct UITableViewControllers, but now you can do them all visually. Remember less code usually means less bugs. There is a lot more cool stuff to check out here with static table views, but we have a lot more to cover so let's move on.
Prototype Table View Cells
Of course you can use the classical UITableViewDataSource protocol methods to define a table views content programmatically. This will still likely be required for most of your table views. However, storyboards also offers some help here. Interface Builder now has much greater support for defining custom UITableViewCells visually. When you do this, you layout the UI elements in the cell as you would imagine, and the final step is to provide the table view cell with a reuseIdentifier.
With this done you can get an instance of the table view cell by using the following for your tableView:cellForRowAtIndexPath: data source method:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *CellIdentifier = @"dyncamicCell"; UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier]; if (cell == nil) { cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier] autorelease]; } cell.textLabel.text = [NSString stringWithFormat:@"Section: %d Row: %d Sum: %d Product: %d", indexPath.section, indexPath.row, (indexPath.section+indexPath.row), (indexPath.section*indexPath.row)]; return cell; }
Navigating with Segues
So, besides all these beautiful static and dynamic view controllers, you can see I have arrows connecting all the scenes together. This is the second important piece to storyboarding. These arrows are new UIStoryboardSegue objects. These represent things like pushing view controllers onto navigation controller, presenting views modally, and whatever other kind of custom segue you can think of creating. The segues are as easy to implement as dragging a connection between two scenes. Any button or Gesture Recognizer (which by the way is also now configurable for views in IB, there is a ton of new stuff here!) can have a "push", "modal" or "custom" segue connection specified in the Storyboard. All of this is very simple to configure with the Storyboard editor, and you will get an end result that's something like this:
So, all of this can be accomplished without writing any code. An interesting use case emerges with presenting scenes modally. When this happens, you are not provided a navigation controller back button by default, so you will need to have a regular IBAction to call when the scene should be dismissed. But in the case of modally presenting scenes through storyboarding, you do the following:
- (IBAction)done:(id)sender { [self dismissModalViewControllerAnimated:YES]; }
Despite the introduction of the presentingViewController property on UIViewControllers in iOS 5, when dismissing modal views that were presented by storyboarding, you call dismissModalViewControllerAnimated: on the modally presented view controller rather then on its parentViewController or presentingViewController.
If you want to dig deep into Storyboarding, you can look into creating your own custom UIStoryboardSegue. The subclassing of UIStoryboardSegue mostly involves overriding:
-(void)perform;
I have done a simple fade segue example with the sample project mentioned above. This is a somewhat unique class to subclass. From Apple's documentation, your responsibilities if you choose to do this are:
Regardless of how you perform the animation, at the end of it, you are responsible for installing the destination view controller (and its views) in the right place so that it can handle events.
You would probably use some core animation here, and no doubt we will see some interesting open source UIStoryboardSegue subclasses coming. I use a simple UIView helper method to perform a transition and on completion push the new view controller on the navigation controller with no animation. You can see code for the perform method below:
-(void)perform { __block UIViewController *sourceViewController = (UIViewController*)[self sourceViewController]; __block UIViewController *destinationController = (UIViewController*)[self destinationViewController]; [UIView transitionWithView:sourceViewController.navigationController.view duration:.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{ [sourceViewController.navigationController pushViewController:destinationController animated:NO]; } completion:^(BOOL finished) { NSLog(@"Transition Completed"); }]; }
Moving Data Between Controllers
Segues are also important for how you will pass data between these views. When presenting a view, the presenting view controller will have the method:
(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
called. This is your opportunity to send data to the next view, The UIStoryboard segue delivered in the method signature above has a property called destinationViewController which you can pass data to. While this covers the concept of handing data to a view controller, passing data back is a bit more complicated. Apple has enforced using a protocol model. This would need to be done in code, where you would define a protocol in the top most view controller and have the view controller it is passing data back to implement it. This is one of the data passing use cases that has not been addressed by these enhancements to the IB editor, so you'll need to build this protocol manually.
Navigation Controllers Demystified
I have been doing iPhone development since before the SDK even supported Interface Builder. We're talking the very first release. And to this day, on Xcode 4.1 and prior, I would sometimes get confused on which XIB was supposed to hold my Navigation Controller and how I exactly set that up. Well it seems like Apple has heard the cries of developers on this, because there is now a new beautiful option to encompass view controllers in IB in Navigation Controller and Tab Bar Controllers. The new option is available in Editor -> Embed In -> Navigation Controller. You can see an image of the option below. When you have a view controller selected and select one of these options, Interface Builder will do the work for you of creating the appropriate holding container and injecting it with the view controller you have embedded within. This is one of my favorite new feature of the IDE because it represents Apple really starting to tailor Xcode for iOS development.
Team Workflow Disruption
The final possible effect Storyboarding could have in the coming years of team based iOS app development comes in how you can deliver components. Apple has shown examples of being delivered static libraries (.a files) from other teams and being able to drop in whole flowing sections of an application from these few very modular files. The pattern shown involves the bundle containing a compiled .a static library, a base view controller header file, and a .storyboard file. With these components you can now instantiate a new UIStoryboard from their storyboard file, pass data into the exposed base view controller, and then present it. The library delivered from the other team could have as many view controllers, web service interactions, or any other functional components, but the team using this code will only have to deal with 3 elements. With this approach being promoted by Apple, I wouldn't be surprised to see more developments in Xcode to endorse this type of workflow. If you are going to be working on a big modern app with a distributed team this could be valuable to consider!
Comments