Add a navigation button

This will pickup where Create a view left off. So you can pick it up from there and download the source. You probably don’t even need the source but grab it if you wish

Now when you create a new view, in that view you might want to place a button in the navigation bar. This is pretty easy to do. So you want to open up the sub-view controller. In my example I called it BrowseViewController. So I will open up BrowseViewController.m and look for the loadView function. In my example you will see it commented ( /* */ ) out. For example.

/*
 Implement loadView if you want to create a view hierarchy programmatically
- (void)loadView {
}
 */

You will notice it is all green. To make it that function work just remove the /* and */ (don’t forget the comment text also) around it so now it looks like

- (void)loadView {

}

Now we want to add a button. So we just add in some code.

	UIBarButtonItem *addButton = [[[UIBarButtonItem alloc]
								   initWithTitle:NSLocalizedString(@"Something", @"")
								   style:UIBarButtonItemStyleBordered
								   target:self
								   action:@selector(doSomething)] autorelease];
	self.navigationItem.rightBarButtonItem = addButton;

So you see we are creating a button with text Something. We are also setting the style as a button with a border. the target is the object it will call on button press and the action is the function. We are auto releasing it also so we don’t have to do a [addButton release]; If we were to add that the application would seg fault.

Now you have to create the function doSomething

- (void)doSomething {

}

There ya go.. all done. The final product should look like this.

You can grab the source code here.

Add a back button

Now that we have two views nicely done, we want to be able to navigate back to the main view. We do this with a back view in navigation bar in the top.

Open up RootViewController.m and look for the viewDidLoad function. You want to add the following line to it.

self.title = @"Photoblog";

Then when you click on browse, it will show Photoblog in the back navigation.

Create a view

So today we will create our first view. This takes over where Create a new class left off. So you can grab the source code from there if you need to. I also edited the arrows for the rows by following this tutorial I created.

Also in the DataController.m class I am changing the names to something more meaningful.

	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Browse", @""), @"title",
						  nil,
						  nil]];

	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Options", @""), @"title",
						  nil,
						  nil]];

Now we want to create a new view. So double click on RootViewController.xib and it will launch IB (Interface Builder). We don’t need to edit or change anything here, it was just a quick way of loading IB up. So now lets go to File -> New and choose a View.

Now to make things simple, make sure the Library is opened by choosing Tools -> Library. Then select the Inputs & Values and drag a label over to the view and drop it there. So now our view looks like this

Now we want to save the view as a .xib file which for some reason Apple calls a NIB. I don’t know why the file extension is different.

So choose File -> Save. I am doing this just for the Browse option, so I am calling this the BrowseView. Make sure you save it in the directory that you use for your project. If you do it will prompt you if you want to add it to the project and make sure you do.

Now if you view Xcode it will save it in the right hand panel of the left hand menu. I like to drag the BrowseView.xib into the Resources directory.

Now we need to add a new controller to the project. Remember in MVC every view must have a controller. A controller will show the view and handle everything that is on the view. So if you add a button, the controller will handle what that button does when someone clicks it.

So in Xcode choose File -> New File and select the UIViewController subclass. You will want to give it the name of BrowseViewController.m

Now that the new class is in your project lets write some code!

Open up DataController.m and look for the createData function. Now we listed 2 nils in our dictionary, we want to change this but just for browse right now. So now the createData looks like this.

-(void) createData {
	menuArray = [[NSMutableArray alloc] init];

	BrowseViewController *controller = [[BrowseViewController alloc] initWithNibName:@"BrowseView" bundle:nil];
	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Browse", @""), @"title",
						  controller, @"view",
						  nil]];
	[controller release];

	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Options", @""), @"title",
						  nil,
						  nil]];
}

So you can see above we init the browseController

In the same file we need to include the new controller so at top put

#import "BrowseViewController.h"

Open up RootViewController.h

We want to import the new class we just created. So you want to top to look like

#import
#import "DataController.h"
#import "BrowseViewController.h"

Now we need to init the controller in the class So your class declaration should look like this with the new BrowseViewController in it.

@interface RootViewController : UITableViewController {
	DataController *dataController;
	BrowseViewController *bvController;  // added this
}

@property (nonatomic, retain) DataController *dataController;
@property (nonatomic, retain) BrowseViewController *bvController;  // added this

@end

Now open up RootViewController.m and add a synthesize for the new controller.

@synthesize dataController, bvController;

Now look for the function didSelectRowAtIndexPath. It should be blank now make i look like this

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
	 // Navigation logic
	 NSDictionary *itemAtIndex = (NSDictionary *)[dataController getItem:indexPath.row];

	 if ([itemAtIndex objectForKey:@"view"] != nil) {
		 self.bvController = [itemAtIndex objectForKey:@"view"];

		 [self.navigationController pushViewController:self.bvController animated:YES];
	 }
}

So there we check if the view is nil, if it is not nil then load the view. So when we are ready to build our application we can click browse and it will go to that view but if we click options it does nothing.

Now we want to release the memory

- (void)dealloc {
	[dataController release];
	[bvController release];  // added this
	[super dealloc];
}

Now that all the code is done, we have to connect things in IB. So double click on the BrowseView.xib file and IB will launch. Now make sure you have the File’s Owner selected and in the Class Identity (Tools -> Identities Inspector) make sure the class is BrowseViewController is selected. It should be listed in the drop down.

Now select the View and make sure View Connections is open (Tools -> Connections Inspector)

You will just see this

So click on the circle on the left of New Referencing Outlet and hold the click down. As you move your mouse around move your mouse over the File’s Owner

So when you release the mouse over File’s Owner. A box will popup to choose View. Make sure you click on the View. So now it will look like this

Now save your xib. File -> Save and in Xcode build and go. So the main screen looks like

If you click on browse you should get

Still nothing happens if we click on Options which is what we wanted. As always you can grab the source here.

Add Arrows to rows

I found a something a bit late what would of been nice to cover before. I guess it is better late then never right?

In offical IPhone apps there are arrows on each row you can click on that mean you can click here to users. We want to add these nice little arrows.

So open up RootViewController.m and look for the function cellForRowAtIndexPath and in the if (cell == nil) {} block you want to add a link for accessoryType so it looks like

	if (cell == nil) {
		cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:MyIdentifier] autorelease];
		cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator;
	}

Your lists should now look like

No source code for this since it was just a one line change

Create a new class

So now that we have a working navigation based application. (download source here) We now want to move the data outside to a seperate class. We do this so we can use the data around the application and not just RootViewController class.

Do you get why? Its so we can use the data in the next view we will get into later.

So the first thing you want to do is create a data holder class. I will call it DataController.m/.h. So the first thing you want to do is right click on the Classes folder on the left hand menu. Then go Add -> New File.

You want to choose the NSObject subclass.

Give it the name DataController. Now that the file is created you will see you have two new files in Classes called DataController.h and DataController.m.

Now we want to move the array over. So the DataController.h looks like

#import 

@interface DataController : NSObject {
    NSMutableArray *menuArray;
}

@property (nonatomic, copy, readwrite) NSMutableArray *menuArray;

- (NSInteger)getCount;
- (id) getItem:(NSInteger)index;
- (void)createData;

@end

So you can see we moved the menuArray array in and we also added a new function called getCount. Later we will use that to return the number of items in the menuArray

So open up the DataController.m. So below @implementation DataController we want to synthesize the array so now your .m file looks like

@implementation DataController

@synthesize menuArray;

@end

You use the @synthesize keyword to tell the compiler that it should synthesize the setter and/or getter methods for the property if you do not supply them within the @implementation block.

So now we need to init the data in the class.

So we need to add an init function. Below the @synthesize you want to add something that looks like

- (id)init {
    if (self = [super init]) {
        [self createData];
    }
    return self;
}

So now we need to create a createDemo function in the class. What I am basically doing is moving all the array items from the RootViewController over to this function.

-(void) createData {
	menuArray = [[NSMutableArray alloc] init];

	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Hello World", @""), @"title",
						  nil,
						  nil]];

	[menuArray addObject:[NSDictionary dictionaryWithObjectsAndKeys:
						  NSLocalizedString(@"Hello Universe", @""), @"title",
						  nil,
						  nil]];
}

Now we want to return the count of the current array to an outside class. So we add in this function.

-(NSInteger)getCount {
	return [menuArray count];
}

We also need to return the item. Since we are displaying these items it will help to return an item at a given index. So add this function in also

- (id)getItem:(NSInteger)index {
    return [menuArray objectAtIndex:index];
}

So what that function says is when called it expects a index to come in as a NSInteger type. It will use that to get the item at that index in the menuArray and it will return it.

Now you want to remove all the instances of menuArray in the RootViewController.h and RootViewController.m. Since we are not using it anymore.

So now back to the RootViewController.m. We need to initialize our new DataController class, so in the viewDidLoad function we want to add the following.

    DataController *controller = [[DataController alloc] init];
    self.dataController = controller;
    [controller release];

Now in the numberOfRowsInSection, we want to return the current count of the menuArray that is now inside the DataController. This is why we made the getCount function, so we can get that count.

So the function should now look like this

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
	return [dataController getCount];
}

Now look for the cellForRowAtIndexPath function and you need to add in setting up the text

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

	static NSString *MyIdentifier = @"MyIdentifier";

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

	NSDictionary *itemAtIndex = (NSDictionary *)[dataController getItem:indexPath.row];
	cell.text = [itemAtIndex objectForKey:@"title"];

	// Set up the cell
	return cell;
}

So you can see there, we are grabbing the dictionary from the array and then using the title key to grab out the title for each row at a certain index.

As always you can grab the source code here.

Next Page →