Site Search
Tweets
invasivecode: @vicentevicens not in the US... I should be able to buy in the Store.2 hours ago from Twitter for iPad
vicentevicens: @invasivecode take into account that you have to call Apple Store Online to get that discount and that it will disappear this year.11 hours ago from Twitter for iPad
Categories
- Apple
- Apple Developer Tools
- Augmented reality
- Branding
- Cocoa Gurus
- CocoaHeads
- Core Graphics
- Dev Technique
- Iniciador
- Instruments
- iNVASIVECODE
- iOS
- iPad
- iPhone
- iPhone App
- iPhone Dev
- iPhone Training
- Legal
- Legal aspects
- MapKit
- Marketing
- Press
- Quartz
- Style
- UIActionSheet
- UIAlert
- UIKit
- UITabBarController
- Uncategorized
- WWDC
- Xcode
- Xcode 4
Tags
Implementing a navigation controller (UINavigationController) with Interface Builder
During the different SDK releases, Apple has changed many things. Now, developers can build their own applications using different approaches, but I personally believe that an intensive use of Interface Builder is a good strategy to set up in few minutes a project and easily maintain it.
During my trainings, I collected the request of my students and most of the time, they wish to use more and more Interface Builder, because it is more intuitive and easier to use than simply typing code.
In this post, I want to explain how to build the infrastructure for the UINavigationController using Interface Builder. I think this is the best, cleanest and quickest way to build an app. If you just repeat this exercise a couple of times to understand the concept, you will be able to build a navigation controller-based app in few minutes.
To better understand what we do, I will start from an window-based project without taking advantage of the view-based template prepared by Apple. So, open Xcode and create a new project. Select a Window-based Application template and name it MyNav. We could have chosen the View-based Application template and Xcode would have setup the whole infrastructure for us, but then you loose all the magic behind it. So, I prefer you build it from the scratch, so that you will learn how it works and you can easily modify it to create more complex functionalities.
Give a look at the created project. It contains three files: MyNavAppDelegate.h, MyNavAppDelegate.m and MainWindow.xib. We need to modify these three files to go on, but let us start with some design.
Suppose you want to navigate 3 views: view1, view2 and view3. The view1 is the view appearing as soon as the app finishes launching. This is called the main view. Since it is the first view in the sequence, view1 is also called the root view. Root view and main View do not always coincide. For example, in the Contacts app, the main view is the All Contacts list, while the Root View is the Groups view.
Each view of our project will be a UIViewController and the Navigation Controller will be responsible to push or pop the next or the previous view onto the screen as they were in a stack. So, let us start.
Modify the MyNavAppDelegate.h file, so that it looks as follows:
1 2 3 4 5 6 7 8 9 10 11 | #import <UIKit/UIKit.h> @interface MyNavAppDelegate : NSObject { IBOutlet UIWindow *window; IBOutlet UINavigationController *myNavController; } @property (nonatomic, retain) IBOutlet UIWindow *window; @property (nonatomic, retain) IBOutlet UINavigationController *myNavController; @end |
Now, let us modify the implementation file. Edit the MyNavAppDelegate.m file like this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | #import "MyNavAppDelegate.h" @implementation MyNavAppDelegate @synthesize window; @synthesize myNavController; - (void)applicationDidFinishLaunching:(UIApplication *)application { [window addSubview:myNavController.view]; [window makeKeyAndVisible]; } - (void)dealloc { [myNavController release]; [window release]; [super dealloc]; } @end |
Now, fire up Interface Builder, double-clicking the MainWindow.xib file. From the Library drag a Navigation Controller and drop it in the MainWindow.xib.
Control-click the My Nav App Delegate object in the MainWindow.xib window and, when the HUD window opens, connect the myNavController outlet with the recently added Navigation Controller.
So, what have we done in the last part? It is very simple: we declared in the @interface of the MyNavAppDelegate a UINavigationController outlet. In the @implementation, we should have allocated and initialized this UINavigationController, but to avoid this, we added a Navigation Controller object with Interface Builder to our project. In this way, the XIB file contains the Navigation Controller. When we launch the app, the MainWindow.xib file, containing the Navigation Controller, is automatically loaded. Since this is a generic object to let Xcode understand that we are referring to the same Navigation Controller defined in the @interface, we need to connect the outlet of the App Delegate to the UINavigationController.
Now, we need to add the 3 UIViewController(s) to manage each view in the stack. The use of the UIViewController instead of simple UIView is requested by the fact that a UIViewController is a controller and thus, it is able to manage complex functionalities, such as screen rotations, that maybe you will use later.
The approach to setup a UIViewController and its XIB file is the same for each view, so I show you how to do it only for one of them. Then, you simply repeat the following steps:
- Right-click the Classes group in the project window of Xcode and select Add->New File…
- Select the UIViewController subclass template from the Cocoa Touch Classes and click Next.
- Name the view FirstViewController (make sure that the Also Created flag is selected) and click Finish. You get two files (FirstViewController.h and FirstViewController.m).
- Right-click again the Classes group and choose Add -> New File… This time, select View XIB template from the User Interface under iPhone.
- Click Next and name the file FirstViewController.xib.
- Click Finish.
Repeat the last paragraph for the second and third view (name them SeconViewController and ThirdViewController).
When you have the three controllers, double click the FirstViewController.xib. The MainWindow.xib window contains 3 objects: File’s Owner, First Responder and View. The File’s Owner is a Proxy Object: it simply represents in IB an object that you have created somewhere else (coding or using IB). We need to specify which object is exactly. To do this, select the File’s Owner and the Identity pane in the Interface Builder Inspector (Tools -> Identity Inspector). Choose as Class name FirstViewController. Repeat this step for the SecondViewController and for the ThirdViewController. When done, you have clearly associated each class to its XIB file.
Now, our File’s Owner represents the FirstViewController object. Right-click it and connect the view outlet with the View object. Open the View object (double-click it) and select the Attributes pane in the Inspector (Tools -> Attributes Inspector). Click on the Background color picker and change the color to red, so that we can distinguish it from the other views we are going to set up.
Now, we have to tell the Navigation Controller that the FirstViewController is the first view we want to load (the Main View, remember?) and use it as root view. Here, there is a small trick. Open again the MainWindow.xib file and double click the Navigation Controller. Click in the window of the Navigation Controller and select the Identity Inspector.
Select as class name FirstViewController. Then, select the Attributes Pane and select FirstViewController as NIB Name. The Navigation Controller should show now a link to the FirstViewController.xib as shown here on the right-hand side. Before you can Build and Run, choose the Detailed View of the MainWindow.xib. Click on the triangle close to the UINavigationController. Inside it, there is UIViewController. You need to make sure that this is is the right one. Select it and set its class name to FirstViewController in the Identity Inspector. In the same way, set to FirstViewController, the XIB Name to FirstViewController in the Attributes Inspector. If you miss these steps, your app will not work. It should look like in the following picture.
You can now Build and Run. You will get a window with a NavigationBar and red view. Let’s go back to the project.
So, we have set our root view. Now, we have to inform each view about the next view of the desired view sequence. You will see that many functionalities are for free and the code we are going to write is represented by few lines.
Edit the FirstViewController.h so that it looks like this:
1 2 3 4 5 6 7 8 9 10 11 | #import <UIKit/UIKit.h> @class SecondViewController; @interface FirstViewController : UIViewController { IBOutlet SecondViewController *mySecondViewController; } @property (nonatomic, retain) IBOutlet SecondViewController *mySecondViewController; @end |
Remember to synthesize the property and add the following header #import “SecondViewController.h” in the FirstViewController.m file.
Now, open the FirstViewController.xib and add a UIViewController to the MainWindow.xib FirstViewController.xib window. Select this view controller and set its class name to SecondViewController in the Identity Inspector. Then, set also to SecondViewController the XIB Name in the Attributes Inspector. Now, finally, connect the File’s Owner outlet mySecondViewController to the view controller.
We do the same for the second view controller. Before that, open the SecondViewController.xib file and add a UIViewController object to the MainWindow.xib SecondViewController.xib window. Select this view controller and set its class to the ThirdViewController in the Identity Inspector and set its XIB Name to ThirdViewController in the Attributes Inspector.
Now, open the SecondViewController.h file and modify it as follows:
1 2 3 4 5 6 7 8 9 10 | #import <UIKit/UIKit.h> @class ThirdViewController; @interface SecondViewController : UIViewController { IBOutlet ThirdViewController *myThirdViewController; } @property (nonatomic, retain) IBOutlet ThirdViewController *myThirdViewController; @end |
Remember to synthesize the property and add the following header #import “ThirdViewController.h” in the SecondViewController.m file.
Now, build and run it. You don’t see any difference with the previous run. The infrastructure is already set up, but we need to add some way to push the next view to the screen. We can do it in different way. We choose the simplest one, using a push button in the center of the current view.
Add a button to the first and second view controllers. For each of them, add the following action in the header file of the corresponding class:
1 | - (IBAction)bringNextView:(id)sender; |
In the implementation, add the following:
1 2 3 4 | - (IBAction)bringNextView:(id)sender { [[self navigationController] pushViewController:mySecondViewController animated:YES]; } |
Repeat the previous code for the second view controller. Don’t forget to connect the button to the IBAction of the File’s Owner. I attach the project MyNav.zip. I only add small things to make it to like nicer. If you have any question, simply contact me.
Have a nice coding!!!


Nice article!
I can’t find the ZIP file attached. Where’s it?
Thanks for reporting that to me.
Now, I uploaded it.
Nice illustration…
Its very simplified and I just understood going only once..
Thanks..
Thanks for the clues. The lack of effective documentation in this area makes this simple task, hard.
Great tutorial! Really explains a lot of the ability of the XIB file to do more for you.
One thing I did notice is that for newer versions of XCode and SnowLeapard there’s an option to add XIB files when you add UIViewControllers which automagically sets up XIB associations with File ownership. Saves even more time but it is more understandable the way you are informing people about how to do this since there is a better sense of how the XIB files get hooked up to associated implementation files.
indeed it’s a good guide for starting.Thanks to the creater, hope to produce more usefull guide.
Excellent presentation. I can tell that you are an excellent trainer. You have made a complex subject very simple. Apple, are you listening?
I do not see pictures of windows of IB that you are refering to. Is te my browser or those are missing in the presentation?
Thank you very much.
Which pictures are you referring to?
Geppy
Simple and Objective, Excellent presentation and code too, Please submit more examples!
Best regards
Hector
Very good post !! Very useful.
Nice tutorial. I used this tutorial to start my app. The issue I have is when each view controller is pushed what method is called always? ViewDidLoad is called only the first time. What would I need to do to make sure a particular view controller’s method is called always when the view is pushed.
-viewDidLoad is online executed after the nib is loaded in memory. If you want to execute something every time the view appears on the screen, you need to use the -viewWillAppear: or the -viewDidAppear: methods. When you use these methods and their counterparts (-viewWillDisappear: and -viewDidDisappear:), you need to execute the same method on the superclass. For example,
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
/* your code goes here */
}
I hope this is helpful.
Geppy
Very useful tutorial.
Does anyone know how to programmatically change the Navigation Controller’s title?
I tried navCtrl.title=@”New title”, but it did not change the title.
Great tutorial, Thanks
Outstanding tutorial!
Thanks
But what if you wanted to have a button for each view and the user can choose which view to go to?
Not just in stack order.
Dave
Same as for the example. You implement the buttons and in the code of each button action, you push the view controller you want.
Finally, something that makes sense. Thanks for uploading this… it really made the subject quite simple. Apple goes into detail on how to use a UIViewController with a UITabController; however, they don’t discuss how to push additional UIViewControllers within the root controller. Thanks Thanks Thanks!