Tutorial: Storyboard in XCode 4.2 with Navigation Controller and Tabbar Controller (Part 2)

Hello again!  If you’re reading this tutorial I’m going to assume that you read part 1 and are ready to continue.  In this tutorial we will take the project from part 1 and expand the second tab (the table) to include some actual table data and a transition to a ‘detail’ screen.  In this instance I’m using movie names and movie images to make it look pretty.  There’s a tiny bit of coding taking place here, but nothing exceptional.  We won’t be making use of Core Data at this stage, just to keep things simple.  Lets get on with it shall we?  (*keep in mind this was written in a hurry, but has been tested!*)

Before we begin, you’ll need the original project (where we left off in part 1) and the table images. You can get them both here…

Get the project from part 1 here – Storyboard complete demo (part 1)

Get the table images here - Table Images for Storyboard tutorial

 

Getting Started / New View Controller

First of all, unpack the images zip file you downloaded above and drag the images into the Supporting Files group in your project.  There should be eight of them (0 through to 7).  Once you’ve dragged in those images we need to create a new View Controller.  We’re going to use this for our ‘detail view’ once a movie has been selected in the table.   So, create a new file (File -> New -> New file).  Choose UIViewController subclass.  Give it a class name of Tab2_ItemViewController and untick both boxes.  Good stuff.

We may as well set up the code for this new class now (it’s not complex).  So open up Tab2_ItemViewController.h and change its content to this….

#import <UIKit/UIKit.h>
 
@interface Tab2_ItemViewController : UIViewController
{
    NSString *selectedItem;
    NSInteger selectedIndex;
    IBOutlet UILabel *outputLabel;
    IBOutlet UIImageView *outputImage;
}
 
@property (nonatomic) NSInteger selectedIndex;
@property (nonatomic, retain) NSString *selectedItem;
 
@end

 

As you can see, all we are doing here is creating some instance variables we will use to hold our selected movie name (selectedItem) and the table row index (selectedIndex) which we will use to display the related image. We also define some outlets for Interface Builder to display the details.  Now open up Tab2_ItemViewController.m and change its content to this…

#import "Tab2_ItemViewController.h"
 
@implementation Tab2_ItemViewController
 
@synthesize selectedIndex, selectedItem;
 
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    [outputLabel setText:selectedItem];
    [outputImage setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg", selectedIndex]]];
}
 
@end

 

Nothing much going on here either really.  Note though, I’ve stripped out all the predefined boilerplate junk which I won’t be using for the demo.  What we’re left with is the viewDidLoad method which is simply setting a label and image which we’re going to create in Interface Builder in just a moment.

 

Creating a data source for the table

Next we are going to edit our TableViewController to give our app somewhere to grab it’s data.  Ordinarily I’d use Core Data for this purpose but wanted to keep this fairly simple.  Instead, we are going to use a very basic array which will hold a bunch of movie names (Kevin Smith movies – my favourites!).   Let’s do the edits first and then i’ll explain what’s going on.  Open up Tab2_TableViewController.h and change it to the following…

#import <UIKit/UIKit.h>
 
@interface Tab2_TableViewController : UITableViewController
{
    NSMutableArray *myData;
}
 
@end

 

Again, nothing spectacular going on here.  We are simply declaring an array to store our table data.  Now open up Tab2_TableViewController.m and change it to the following….

#import "Tab2_TableViewController.h"
#import "Tab2_ItemViewController.h"
 
@implementation Tab2_TableViewController
 
// When the view loads, define our data
- (void)viewDidLoad
{
    [super viewDidLoad];
 
    // Define our test data
    myData = [NSMutableArray arrayWithObjects:
              @"Chasing Amy",
              @"Mallrats",
              @"Dogma",
              @"Clerks",
              @"Jay &amp; Silent Bob Strike Back",
              @"Red State",
              @"Cop Out",
              @"Jersey Girl",
              nil];
}
 
// Return number of sections in table (always 1 for this demo!)
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    return 1;
}
 
// Return the amount of items in our table (the total items in our array above)
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return [myData count];
}
 
// Return a cell for the table
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    // A cell identifier which matches our identifier in IB
    static NSString *CellIdentifier = @"CellIdentifier";
 
    // Create or reuse a cell
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
    }
 
    // Get the cell label using its tag and set it
    UILabel *cellLabel = (UILabel *)[cell viewWithTag:1];
    [cellLabel setText:[myData objectAtIndex:indexPath.row]];
 
    // get the cell imageview using its tag and set it
    UIImageView *cellImage = (UIImageView *)[cell viewWithTag:2];
    [cellImage setImage:[UIImage imageNamed:[NSString stringWithFormat:@"%d.jpg", indexPath.row]]];
 
    return cell;
}
 
// Do some customisation of our new view when a table item has been selected
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
    // Make sure we're referring to the correct segue
    if ([[segue identifier] isEqualToString:@"ShowSelectedMovie"]) {
 
        // Get reference to the destination view controller
        Tab2_ItemViewController *vc = [segue destinationViewController];
 
        // get the selected index
        NSInteger selectedIndex = [[self.tableView indexPathForSelectedRow] row];
 
        // Pass the name and index of our film
        [vc setSelectedItem:[NSString stringWithFormat:@"%@", [myData objectAtIndex:selectedIndex]]];
        [vc setSelectedIndex:selectedIndex];
    }
}
 
@end

 

Okay, again I’ve stripped out a lot of boilerplate code which you may see in your original file and littered some comments around.  In our viewDidLoad method, we are defining the contents of our data array (the items which will appear in the table) – eight items in total.  Next, we return number of sections and number of rows in the table.  Following that, we have our cellForRowAtIndexPath: method which returns a single cell for the table.  In this method we either reuse or create a table cell and populate it with a title and an image which we will set up in a moment.  I’m using the ‘tag’ value to identify elements in my table cell.

Finally, we come to a new method for iOS5 called prepareForSegue:sender: which is an important addition to the storyboarding.  This method is linked by a specified identifier to a segue from the storyboard (you know those link thingies which link all your views together).  The method is called after your view is initialised and before it is displayed, so we use this method to do some customisation (in this instance, we’re using it to pass the title of our selected movie and the selected table index row so we can figure out which image to use.   So stepping through this method, you see that we first check to see if the segue identifier matches the one we will set in just a moment.  Then we grab a reference to the view controller we’re about to display (remember, at this stage its already been initialised).  Then we simply set the instance vars we defined earlier.

And that’s all the coding that’s required.  The rest we will do in the storyboard.

 

Storyboard Revisited

Right, so now we only have to hook everything up and we’re ready to roll!   Open up the storyboard file again and click on the (Tab2 Table View Controller) table view.  Under ‘style‘ choose grouped.  I prefer grouped tables for looks.  Now select the blank (prototype) cell and in the Identifier box, type in CellIdentifier (no spaces).  This must match exactly the name used in the cellForRowAtIndexPath: method.  If we were to run at this point we would see a blank table with eight entries but no data.  We need to put a label and an image view into that blank cell.  Drag in a UILabel from the Objects list (Utility panel) and put it somewhere in the blank cell.  Do the same with a UIImageView.  This should automatically resize to around 35 x 35 pixels when dragged into the empty cell.  Arrange it something like this…

I’ve chosen to put my image view on the left and my label on the right (with right justification).  Feel free to be creative with your layout!  Now, most important – we’re going to use the Tag value to identify these two elements when we draw the table content, so first select your label and change Tag value to 1 (you can find Tag under the Attributes Inspector – third icon from right in the Utility panel).  Next, select the UIImageView and change its tag value to 2.   Go ahead and run your project – under Tab 2 View you should now see a rather satisfying table complete with titles and images…

When we select a row, it’d be nice to see how to push a new view with some details.  We’re only going to show the same label and image in its own view – but you could of course, use this for anything at all (editing etc).  Earlier on we created a new class called Tab2_ItemViewController.  It’s already locked and loaded for use here, so lets drag a brand new UIViewController just to the right of our table.  Once it’s in place, select it and in the Identity Inspector (third icon from left in utility panel) change the class to Tab2_ItemViewController.  Now go back and select the cell in the table view (making sure it IS the cell you select and not the label!) and CTRL+Click drag (or right-click drag) to our newly created View Controller.  Choose ‘Push‘ from the submenu.  You’ll notice the navigation bar will be automatically added – why not take this chance to double click the bar and give it a title…. say “Movie Details” or something.   Something else happened here which you may not have noticed.  When we connected the table cell, it was automatically given a disclosure indicator (the chevron on the right hand side).  Just make sure it’s not being overlapped by your label or image and adjust if needed.

Hang in there…. almost done.  On your new view controller, drag in a UILabel and a UIImageView.  You can make the image view 70 x 70 pixels in the Size Inspector if you like.   Arrange them however you like.   I’ve made my label the width of the view and centred.  I’ve put the image right underneath it – and made the whole view background colour a horrid pink.   When you’re done, we need to connect these two elements up.  Simply CTRL+Click drag (or right-click drag) from the status bar (where the battery icon is!) to the label and choose outputLabel.  Then again from the status bar to the image view and choose outputImage.

And now the final, final step.  Remember earlier in our code where we specified a name for our Segue?  Well we now need to name that Segue.  Click the connection between the tableview and the view controller and in the Attributes Inspector, for the identifier enter the name ShowSelectedMovie.  Remember it must match exactly the one we used in the prepareForSegue: method earlier.   Here’s what the finished storyboard should look like roughly (except perhaps the pink background!)

That’s all!  We’re done.  Quick…. go and try your work of art.   Everything should function perfectly…. if you select a table row, we will now see the movie details.  Job done!

You can get the finished project here!  Please comment if you enjoyed the tutorial or it helped you out.

Final Storyboard Tutorial Project


Comments are now closed for this tutorial but I’d still love to hear from you. You can post in our integrated forum by clicking this link (or by going to the Discussion Forum tab at the top of the page)

26 Comments.

  1. Hello!
    Thank you for this tutorial!
    I am a beginner and I would want to know how I could add in Movie Detail view a text wichi correspond to the description of each movie…? Have I to create a new array as we did for the labal? (I would want to use Text View..)

    Thanks a lot ! :)

  2. Ideally you should really be using Core Data to keep your data together. The tutorial was really to demonstrate the transition from screen to screen using the storyboarding in XCode.

    If you really wanted to do it this way, you could easily add another array called myData2 or something and store your descriptions in there. Better still, create a new class which stores a single movies details and fill the myData array with those movie objects.

    I’d still recommend checking out Core Data for a better way to store data. XCode 4.2 provides boilerplate code for creating projects with Core Data included so you should be able to piece it together from there.

  3. Ok I will have a look to Core Data…
    Thanks a lot for your quick reply!

  4. Again – excellent tutorial. Thanks! :grin:

  5. Is there a way to make a common control that is used by two Views?

    For example, say I want to have a common way to show the details of a Movie {thumbnail, Title, Year} in multiple views.

  6. Yes, you’d just create a subclass of UIViewController and use it wherever you need to. Have to tried this with no success?

  7. Thanks for the reply!

    I’m actually just learning iPhone dev now (coming from an Android background) so I’ve been trying to find good sites/tutorials for such things.

    The storyboard UI editor is great and I want to use this for much of my UI work. I haven’t read about UIViewController so will check that now – thanks for that.

    My only question, which reading will hopefully answer, is if I can use the interface builder to do this subclassed control or if it has to be done in the code?

  8. You’d just create a new file in your project that’s a subclass of UIViewController (we do some in this tutorial)

  9. Hi Simon,
    Thank you so much for this tutorial… it’s really helpful.

    I have a question… is there a way to connect each raw of the tableView with different views by using the Storyboard?

    I assign the location of the item in the array and I want to visit different view according to the location of the item in the tableView.
    But when I tried to connect the tableView with the views, I could connect it to one view.
    Should I use the method: tabelView:didSelectRowAtIndexPath:???

  10. I’d think the best way to do this would be with a static table – but if the contents of the table are always changing that may not be easily possible. You could still use traditional NIB files and didSelectRowAtIndexPath: instead of storyboarding it. Sounds a better fit.

  11. I read that part of the tutorial but don’t see how we can tie a single reusable UI control with the custom UIViewController. I think what you did is reuse the controller for two different UI’s (the cell and the details view).

    What I want is to build a single drag-and-droppable control that I’ve designed that can be reused in multiple views. I mean, in the Storyboard editor there is an Object Library where we have the controls we want to drag-and-drop onto our views. There is a section for “Custom Objects” and I am trying to build a control that will show up there and allow me to drag-and-drop my custom control onto any view I wish.

  12. I’ll try to have a play with this when I get a moment and see if I can better grasp the issue you’re having.

  13. Your code’s breaking for me. It’s saying that it does not declare a method for selectedIndex. Stupid ARC (just kidding, don’t want Apple to take away automatic memory management).

  14. Now it’s coming up with 8 other build-preventing errors.

  15. The downloadable project at the end is breaking with errors? That’s odd cos it works fine if i download and build it. Presumably Xcode 4.2 you’re using with a standard install?

  16. Great tutorial.It clearly showed and explained some important view controller information which i will be able to use as a reference for future work.
    Thanks to all concerned and i will be looking out for more tutorials from maybelost. i will be recommending you to other developers.

  17. Excellent turtorial!!! Thanks very much for sharing! Apple should take this as their official documentation.

  18. :grin: Thanks for your kind words. Knowing it’s helping someone keeps me writing!

  19. Great tutorial.

    Question: How do you add another table after the first one? I would then have the second table push the movie titles?

  20. @nichestl : Exactly the same way you’d push any other view, except with a table! You can still use prepareForSegue to do any configuration work you need to do before you show the new table but the principal is the same as pushing a view controller like the one showing the movie details.

  21. Awesome Tutorial!

    Thank you so much for posting this. Easy to follow! And, if I messed up, I could refer to the posted code. (I tried not to, but sometimes I get too excited and miss a step. Hahaha!!!)

    Really appreciate it and can’t wait for the next tutorial!!!

  22. Brilliant Tutorials. Thank you for taking the time to prepare this. The Segue in the second tutorials was an eye opener.

  23. “Please comment if you enjoyed the tutorial or it helped you out.”

    I did enjoy your tutorial, and it helped out a lot. Thanks.

  24. A very good tutorial. Thank you very much. I’m looking forward to more tutorials from you. Keep up the good work!

  25. Good tutorial. Thank you very much.

  26. DISCUSSION FORUM is now open on this website if you want to ask questions or post comments. You can find it at the top of the page.

    Any and all participation is welcome!