iPhone Dev Sessions: Create a Navigation-Based Application

96 Comments

In this tutorial, you will learn how to do the following:

  • Create and run a Navigation-Based Application from XCode
  • Create and add a user interface, designed in Interface Builder, as a sub-view to a navigation based application
  • Navigate to sub-views from a UITableView
  • Allow sub-views to access application data

Creating and Running a Navigation-Based Application in XCode

Let’s start off by opening up XCode and creating a Navigation-Based Application.

001

Click Choose… and give your application the name BasicNavigation. Once completed, your project window should look like this.

002

At this point, if you click “Build and Go” and have your project selected to run on the iPhone simulator, you should see the application launch and display a bare UITableView, with undefined row elements. No worries, this is going to change very soon. Your app at this point should look like the following below.

003

Adding a Sub-view (Designed in Interface Builder) to a UITableView

We are now going to add a sub-view to our application. This sub-view will consist of three key elements.

  • A Header File (*.h file extension) — Used for defining methods and variables to be used by an accompanied implementation file.
  • An Implementation File (*.m file extension) — Used for implementing methods and accessing variables defined in an accompanied header file. This is where we will place code for view specific logic and functionality.
  • An Interface File (*.xib extension) — Used for defining the visual look of the view, using Interface Builder.

In XCode, within the project area on the left, right-click on the Classes folder and select Add, then New File…. You will be presented with the following dialogue.

004

Make sure you’ve selected Cocoa Touch Classes on the left and select the file template for UIViewController subclass as illustrated above, and click Next. You will be presented with a dialogue in which you will assign a name for this asset. Name this file SubViewOneController.m and make sure the checkbox for Also create ‘SubViewOneController.h’ is checked as well. Click Finish when this is done. The dialogue should look like the following, before clicking on Finish.

005

At this point, you will see two additional files in the Classes folder that we’ve just added. So far we’ve added a header file (SubViewOneController.h) and an implementation file (SubViewOneController.m), which takes care of two out of three key elements. We’ll now add the last element here before moving on towards implementation.

In XCode, right-click the Resources folder and select Add, then New File…. On the left, select User Interfaces and select View XIB and click next. In the next dialogue, you will give this user interface a name. Type SubViewOne.xib under File Nam” and click Finish. These steps are illustrated below.

006

007

The contents of your project window should now look similar to the illustration below.

008

Open the file SubViewOneController.h and add the following code:

@interface SubViewOneController : UIViewController {
IBOutlet UILabel *label;
IBOutlet UIButton *button;
}

@property (retain,nonatomic) IBOutlet UILabel *label;
@property (retain,nonatomic) IBOutlet UIButton *button;

– (IBAction) OnButtonClick:(id) sender;

@end
[/sourcecode]

Open the file “SubViewOneController.m” and add the following code:

[sourcecode language=’csharp’] #import “SubViewOneController.h”

@implementation SubViewOneController

@synthesize label, button;

– (id) init {
self = [super init];
if (self != nil) {
// set the title of this view
self.title = NSLocalizedString(@”Subview One”, @””);
}
return self;
}

– (IBAction) OnButtonClick:(id) sender {
}

– (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn’t have a superview
// Release anything that’s not essential, such as cached data
}

– (void)dealloc {
[super dealloc];
}

@end
[/sourcecode]

What we’ve done thus far is write a bit of view controller code. In our code, we’ve declared a variable for a UILabel and a UIButton. We’ve also created a stubbed handler method for responding on the button click action. What we haven’t done yet is create a user interface to go with our view controller code. Let’s go ahead do that now.

In the project window, let’s expand the Resources node, and double click on the file SubViewOne.xib. You will then see Interface Builder open this file and be presented with a blank View file. In the menu bar, click on Tools, then Library. When the Library window opens, click on the Inputs & Values node. The Library window will look this.

009

Drag a UILabel and a UIButton such that your view mimics the following interface.

010

At this point, if you have not saved and built your project, please do so by going back into XCode and clicking the Build button. If all is well, everything will build successfully. We’re not done just yet, so let’s head back to Interface Builder.

Highlight File’s Owner and then from the menu bar, click on Tools, then Identity Inspector. In the Class text input, type or scroll down to the menu option that says SubViewOneController. Your view properties should now look similar to the following.

011

In the next steps we are going to wire up the user interface elements of the view we’ve created to the view controller we created earlier. First make sure File’s Owner is selected. In the menu bar, click on Tools, then Connections Inspector.

Under Outlets and Received Actions in the Connections Inspector make the following associations:

  • Drag the “button” outlet to the button on the visual interface
  • Drag the “label” outlet to the label on the visual interface
  • Drag the “view” outlet to anywhere on the visual interface
  • Drag the “onButtonClick” action to the button on the visual interface. Select “Touch Up Inside”

012

At this point we’ve created our first sub-view, however we’re not going to be able to get to it from application just yet. That’s the next step.

Before moving on, go back into XCode and click on Build before moving onto the next part. Your build should compile and the results should report back successfully at this point.

Navigating to a Sub-View from a UITableView

The code below will do the following:

  • Sets up an array of views and supplies that array to our UITable as a data source
  • Adds multiple sub views to our application using the sub view we’ve designed and written thus far
  • Allows us to navigate to different sub views upon view selection from our UITableView

Open the file “RootViewController.h” and add the following code:

[sourcecode language=’csharp’] #import

@interface RootViewController : UITableViewController {
IBOutlet NSMutableArray *views;
}

@property (nonatomic, retain) IBOutlet NSMutableArray *views;

@end
[/sourcecode]

Open the file “RootViewController.m” and add the following code:

[sourcecode language=’csharp’] #import “RootViewController.h”
#import “SubViewOneController.h”

@implementation RootViewController

@synthesize views;

– (void)awakeFromNib {
// we’ll keep track of our views in this array
views = [ [NSMutableArray alloc] init];

// allocate a set of views and add to our view array as a dictionary item
SubViewOneController *subViewOneController = [[SubViewOneController alloc] init];
subViewOneController.title = @”Subview One”;
[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
@”Subview One”, @”title”,
subViewOneController, @”controller”,
nil]];
[subViewOneController release];

subViewOneController = [[SubViewOneController alloc] init];
subViewOneController.title = @”Subview Two”;
[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
@”Subview Two”, @”title”,
subViewOneController, @”controller”,
nil]];
[subViewOneController release];

subViewOneController = [[SubViewOneController alloc] init];
subViewOneController.title = @”Subview Three”;
[views addObject:[NSDictionary dictionaryWithObjectsAndKeys:
@”Subview Three”, @”title”,
subViewOneController, @”controller”,
nil]];
[subViewOneController release];

// create a custom navigation bar button and set it to always say “Back”
UIBarButtonItem *temporaryBarButtonItem = [[UIBarButtonItem alloc] init];
temporaryBarButtonItem.title = @”Back”;
self.navigationItem.backBarButtonItem = temporaryBarButtonItem;
[temporaryBarButtonItem release];

//set the title of the main view
self.title = @”Basic Navigation”;
}

– (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn’t have a superview
// Release anything that’s not essential, such as cached data
}

#pragma mark Table view methods

– (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 1;
}

// Customize the number of rows in the table view.
– (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [views count];
}

// Customize the appearance of table view cells.
– (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString *CellIdentifier = @”Cell”;

UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}

// Set up the cell…
cell.text = [[views objectAtIndex:indexPath.row] objectForKey:@”title”];

return cell;
}

– (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic may go here. Create and push another view controller.
UIViewController *targetViewController = [[views objectAtIndex: indexPath.row] objectForKey:@”controller”];
[[self navigationController] pushViewController:targetViewController animated:YES];
}

– (void)dealloc {
[views dealloc];
[super dealloc];
}

@end
[/sourcecode]

Click the “=Build and Go button in XCode. Our application thus far should now allow us to select a sub view and navigate to it. The application should look similar to the following:

013

014

Accessing Global Application Data

In an iPhone application, the Application Delegate can commonly be used to store global variables accessible by all views. You may run into a situation where a view may require data that has been modified by another view or may need to be notified of updates to this data. This piece of the tutorial will cover that very scenario. In this, we’ll be covering some key points in our code:

  • Subscribing to central events
  • Broadcasting events globally
  • Reading/writing global application data

To begin, let’s open the file BasicNavigationAppDelegate.h and add the following code.

[sourcecode language=’csharp’] #import

@interface BasicNavigationAppDelegate : NSObject {

//Application Model Data
NSString *modelData;

UIWindow *window;
UINavigationController *navigationController;
}

@property (nonatomic, retain) IBOutlet UIWindow *window;
@property (nonatomic, retain) IBOutlet UINavigationController *navigationController;

– (void) setModelData:(NSString *)modelData;
– (NSString *) getModelData;

@end
[/sourcecode]

Now open BasicNavigationAppDelegate.m and add the following code.

[sourcecode language=’csharp’] #import “BasicNavigationAppDelegate.h”
#import “RootViewController.h”

@implementation BasicNavigationAppDelegate

@synthesize window;
@synthesize navigationController;

– (void)applicationDidFinishLaunching:(UIApplication *)application {
// Configure and show the window
[window addSubview:[navigationController view]];
[window makeKeyAndVisible];
}

– (void)applicationWillTerminate:(UIApplication *)application {
// Save data if appropriate
}

// accessor methods for “data” property

– (void) setModelData:(NSString *) newData {
modelData = newData;
[[NSNotificationCenter defaultCenter] postNotificationName:@”dataChangeEvent” object:self];
}

– (NSString *) getModelData {
if ( modelData == nil ) {
modelData = @”Hello World”;
}
return modelData;
}

– (void)dealloc {
[navigationController release];
[window release];
[super dealloc];
}

@end
[/sourcecode]

We’ve added a model variable and accessor methods to read and write to this variable. Notice on the setModelData method, how we have the following line [[NSNotificationCenter defaultCenter] postNotificationName:@"dataChangeEvent" object:self]. When this setter method is called, we will be broadcasting an event, dataChangeEvent, to observers of this event notification. For this application, our sub views will subscribe to this event notification.

Go back and open up SubViewController.h and add the following line:

- (void) getModelData;

Now open SubViewOneController.m, and update the code to look like the following:

[sourcecode language=’csharp’] #import “SubViewOneController.h”
#import “BasicNavigationAppDelegate.h”

@implementation SubViewOneController

@synthesize label, button;

– (id) init {
self = [super init];
if (self != nil)
{
// subscribe to changes on global data and course of action to take
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(onDataChangeEvent:)
name:@”dataChangeEvent”
object:nil];
}
return self;

}

– (IBAction) OnButtonClick:(id) sender {
// this view will set our model data
BasicNavigationAppDelegate *appDelegate =
(BasicNavigationAppDelegate *)[[UIApplication sharedApplication] delegate];
NSString *displayString = [NSString stringWithFormat: @”Set By %@”, [self title]];
[appDelegate setModelData:displayString];
}

– (void)onDataChangeEvent:(id) sender {
[self getModelData];
}

-(void)viewWillAppear:(BOOL)animated {
[self getModelData];
}

// set our label to reflect the latest copy of the data that we’re observing
– (void) getModelData {
BasicNavigationAppDelegate *appDelegate =
(BasicNavigationAppDelegate *)[[UIApplication sharedApplication] delegate];
[label setText:[appDelegate getModelData] ];
}

– (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning]; // Releases the view if it doesn’t have a superview
// Release anything that’s not essential, such as cached data
}

– (void)dealloc {
[super dealloc];
}

@end
[/sourcecode]

Let’s note the relevant things that are going on here:

  • The view subscribes to the dataChangeEvent on the init method. When the dataChangeEvent is fired, the method onDataChangeEvent is triggered and executed.
  • On Button click, we will be setting the the model data located in our application delegate. Remember, that in our implementation, whenever that variable is set, the OnDataChangeEvent is fired and all observers of that event will respond to it

Here’s how we know that our sub views are operating off the same global data.

  • Click on Sub View One, then click the button in that view. You’ll notice the label will change to “Set By Subview One”
  • Click “back”, then click on Sub View Two. Notice the label says “Set By Subview One”
  • Click the button, the label should change in Sub View Two to “Set By Subview Two”
  • Click “back, then click on Sub View Three. Notice the label says “Set By Subview Two”

Do you notice what’s happening here? Our data is persisting across views and this data can be read and set by any of our sub views. What we’ve demonstrated here are some very basic practices in model-view-control design and implementation. I hope this lesson carries well for you. Happy coding.

96 Comments

Claudio

I truly appreciate the effort involved with the production of this tutorial. I am however experiencing an issue with this bit of the walkthrough;

change:
[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]
to:
[super initWithNibName:@”SubViewOne” bundle:nil]

Not sure what’s going on here, but I’ve followed the tutorial to the letter and nowhere do I see this original text to replace. That aside I have attempted the following and the app just crashes…

– (id) init{
self = [super initWithNibName:@”SubViewOne” bundle:nil];
if(self != nil){
// set the title ofthis view
self.title = NSLocalizedString(@”SubViewOne”, @””);
}

return self;
}

I have also tried variations as per another walkthrough and it crashes as well…

– (id) initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
if (self = [super initWithNibName:@”SubViewOne” bundle:nil]) {
// Custom initialization
}
return self;
}

Pretty much anything I try breaks the app… Any insight would be greatly appreciated…

Thanks,
C.

JT

I’m on the same page as you, Claudio. I have also followed the tutorial to the letter, and see no place to replace the aforementioned original code. The app is crashing after entering a Sub View, clicking the button, returning to the main view, and then attempting to do this same action again. Additionally, when entering a sub view, the label is not displaying the text intended. It simply says “Hello …” and when the button is pressed, “Set by …”

JO

By SubViewController.h file does he (or she) mean SubViewOneController.h or do I create a SubViewController.h?

Tony

Great tutorial…b.t.w… is it possible to load a new view if the button is pressed inside SubviewOne…How?

SubviewOne gets loaded by pushViewController in the RootViewController.m file, but when the button is clicked on the SubviewOne the control is passed to onClick function inside SubViewOneController.m. I guess my question is how can the next view be pushed onto the Navigation controller in this situation for SubviewOne?

Thanks

Tony

Nevermind … here is the solution…
Create a new view controller the way SubViewOneController is created above and name it something e.g. NewViewController. Add #import “NewViewController.h” on the top of SubViewOneController.m file. Comment out the code inside OnButtonClick and add this

// Pushing another view
– (IBAction) OnButtonClick:(id) sender {

NewViewController *pController = [[NewViewController alloc] initWithNibName:@”NewView” bundle: nil];

[self.navigationController pushViewController:pController animated:YES];

[pController release];

}

Kristoffer

When i have done all these steps the compiler gives me 5 errors.
First it says “Expected specifier-qualifier-list before ‘NSMutableArray'” about the IBOutlet in the RootViewController.h file.
What have i done wrong? Anyone knows?

Thx

Matt Whitby

What do people say; “Not to worry I figured it out.” and never write what they did to fix it?

annie

I followed the tutorial but am getting a ‘SubViewOneController’ undeclared error on line 21 of RootViewController.m file when i try to build and run. I checked all the syntax. Any ideas?

Priya

Hello ,
I am a new iphone app developer . I need some help in creating a table view that shows four subviews like ..

When u click News Feed it should be able to give me
1. Sports
2. Arts
3.Organizations
4.Nearby

houman

For a long time I have been looking for something in such a details and your tut is pretty good, When I click on the button it says (set by…), but I guess I will work on it to see the problem.

Cheers

Shreedevi

hi.. i am new to iphone application development.
i want to design a login page, where the user feeds in his username and password. and on the button click of login button the username and password will be validated , and a new screen should be displayed.

Now on the button click i see only one parameter passed, which is sender
i dont know how to pass 2 parameters.

in my logincontroller.h i have
-(IBAction)Login_Method:(NSString *)username :(NSString *)password ;

Also in logincontroller.m i have
-(IBAction)Login_Method:(NSString *)username :(NSString *)password
{
if([username isEqualstoString: @”aa”] &&[password isEqualToString:@”bb”])
{
// display new view
}
}

Please help me….

Ted M

Just wanted to say how great of a tutorial this is. I have tried other tutorials for navigation based apps that tackle the problem of adding an array to a table in a completley different way which never makes any sense or does not make good use of the NSObject class. This approach is perfect!

I learned way more from this tutorial than any other to date. This just made Object-Oriented programming clear as day for me.

neyo

hello, i just wnat to tel about my business i will to introduc you oto my business iphone dont come but in one condition i will like you to advance me how to state the business because i just stat the business. then i will like you to mail me back to my mail address.

Sweet

Very nice tuto ^^
I would like to go in a other view of RootView when i click in the button. How can i make this ???

Andrew P

I like this! Thank-you!! Now, I’d like to add to the end of a branch (eg from subview one) another list but it’s generated from a db table. Then you touch it for a details view. How to add this data? Create another model-view-control? Must I append the fetched table data to the dictionary you have defined. Any help or code appreciated, I have spent 3 full days trying! Thanks!

gamesmasta

Hi! I was curious if you figured this out? I’m just getting started with this tutorial, but will want to do something similar to what you described.

List of Lessons –> Conversation –> Audio file
–> Vocabulary –> List of vocabulary words –> Audio file for each word

1. List of lessons: Lesson 1, Lesson 2, etc. (SubViews)
2. Conversation & Vocabulary (SubSubViews)
3. Each vocabulary word is displayed and triggers an audio file.

I appreciate any responses and am very thankful for all the posts before me.

BG

Having issue with this line of code

[views addObject:[NSDictionary dictionaryWithObjectAndKeys: @”Subview One”, @”title”, subViewOneController, @”controller”, nil]];

i get a caution (not an error) that says
warning: ‘NSDictionary’ may not respond to ‘+dictionaryWithObjectAndKeys:’

all 3 chunks of code that are adding subviews give me this warning

are there any other tutorials like this?? With sample code?

is there any sample code for this application out there??

that would really be helpful!!

Sunny

@James Revolti I ahd the smae issue and i releazed I was releasing the viewcontroller after it was being pushed. I didnt release it and now evrything is ok.
@ Rom you want to add this line of code to your method to make it go back
[self.navigationController popToRootViewControllerAnimated:YES];

@Julian what you need to do is define a variable that is the viewcontroller but define it as your class. So basically I called my viewControll class subViewOne, so heres the code:
//i named my viewcontroller targetView
UIViewController *targetView =[[views objectAtIndex:indexPath.row] objectForKey:@”controller”];
//then i make an instance of my orignal class that is equal to that targetView
//without this you can access the properties
SubViewOne *myView=(SubViewOne *)targetView;
//the AFTER i pushed it to the navigationController i put this
[myView.label setText:@”hello world”];
//iphone sdk 3.0 [the method would be ]

hit me up on linked in for more questions and i’ll try to get back to you
Sunny Clark flash developer.

Rom

Nice tutorial :)

How to return to the “RootView” menu, when i click on the “Button” button (SubViewOne) ?
What I need to add in the “OnButtonClick” method ?

Brandon

I would also like to know how to navigate to a navigationController from a subview

Greg

Hi there,
great tutorial
but is there a way to not use a table view for the first view?

OGOS

I think in the second code listing you missing to release something….

raj

One minor nit:

When your text says:
# Drag the “button” outlet to the button on the visual interface
# Drag the “label” outlet to the label on the visual interface

the picture which goes along with that actually shows the label outlet being dragged to the button and the button outlet being dragged to the label. :)

Nice tutorial! Thanks!

Julian again

Ok I have a real question. I did everything you said to do in this tutorial. I am just wondering how to make certain text appear when I click the button. (as you can probably see im a real noob)
Since it says “set by…”, I figured that means there is some way to make it say what you want. I have most of the code i need ready. Im trying to make it so when you tap the button it picks a random number and displays the text associated with that number. How do I make that text display on the label in the subview?

Julian

never mind about that comment. I was able to fix it myself.

Julian

I’m encountering trouble at the “Navigating to a Sub-View from a UITableView” part. I just added that huge bunch of code to rootviewcontroller.m , and now it doesn’t work.I get 3 warnings, each at the “SubViewOneController.title = @”Subview Two”;” areas for subview one, subview two, and subview three.
The warnings all say “warning: ‘subviewoneController’ may not respond to ‘-alloc’.”
When I click build and go, it seems to build ok but as soon as the sim phone loads my program it crashes.

I would love some help.

James Revolti

Great tutorial! Congratulations!
It works fine here!

But if I click twice in the button, the program crashes when I select a new view.

Adam Boulanger

The solution to the SubViewOneController’s view not appearing is that you need to tell the controller that the view will be initialized from a nib file. Go into SubViewOneController.m and un-comment the code starting with :
– (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {

change:
[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]
to:
[super initWithNibName:@”SubViewOne” bundle:nil]

then it should load the associated view object from the nib file of that name.

Ranjeet

If u change:

[super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]

to:

return [super initWithNibName:@”SubViewOne” bundle:nil];

it will work fine.

lakshmi

please tell us how add one more view to this we need six frames to view ,please guide us any one its an urgent requirement

dano

Yup – same here. — must be something missing.. I am looking at the apple dev sample for UICatalog to see if I can see what went wrong.

Michele

When I enter in a SubView, I can’t see anything.

There is no button, no label. :(

Comments are closed.