We need create an app that subclasses the UIViewController class. What is supposed to happen essentially is that we should hit a button and navigate to another window. Eventually multiple buttons will take us to different windows. I was initially feeling inspired by my new found confidence in my understanding of InterfaceBuilder. That all came crashing down when I tried applying some new concepts (loading views dynamically). It’s really not all that complex, just more so than I was initially prepared for.
Starting with my applicationDidFinishLaunching method (in my delegate):
navigationController = [[UINavigationController alloc] init];
// instantiate the first view controller (bottom of the stack)
PersonListViewController *listViewController = [[PersonListViewController alloc] initWithNibName:@”PersonListView” bundle:nil];
// push the view controller to the navigation controller
[navigationController pushViewController:listViewController animated:NO];
// the navigation controller now owns the view, let the copy go here
[listViewController release];
// add the navigation controller to the display
[window addSubview:navigationController.view];
// Override point for customization after application launch
[window makeKeyAndVisible];
I’m initializing my navigation controller here first (as opposed to doing it in the nib). Then I init my first view controller. This is going to be the default view for my navigation controller and is going to live on the bottom of the view stack (first on, last off).
Once I’ve pushed my PersonListView to my UINavigationController I’m done with it and can release.
From there I just need to add navigationController to my window and make it visible.
Adding another view
What I need to remember here is that this is calling it’s own nib (initWithNibName). I need to create this nib file, then I need to specify my PersonListViewController class as the File’s Owner, otherwise I get the following error (when trying to load the nib I called PersonListView:
The File’s Owner is an object proxy. The reason for the File’s Owner (as I have come to understand it after reading this thread) is basically to let objects that are currently loaded into your app know about objects that haven’t quite loaded yet so that objects your existing nib have a reference to those pre-existing objects.
Maybe this is a bit of a stretch, but I liken it to the english word “thing” (bear with me). I often use “thing” when I’m unable to immediately recall the actual name of the object I’m referring to. “Thing” is a placeholder while I flesh out the rest of my sentence.
Simply designating my PersonListViewController as the File’s Owner doesn’t get rid of this error though. I need to connect the view object in my nib to the view outlet in my UIViewController subclass (PersonListViewController).
With that figured out I can move on to the navigation part of the assignment. In my PersonListView nib I create a button that I’ll use to trigger the move to the next view in the stack, and the action that handles the button click.
Then I create a new class that subclasses the UIViewController (just like my PersonListViewController) and call it PersonDetailViewController. When the button in PersonListView is clicked I add this view to the stack by pushing the new view to the navigationController:
[[self navigationController] pushViewController:personDetail animated:YES];
A few things to note:
- Dynamically loading and displaying an image:
This was interesting. I initially concocted this (the uImage value was set to “mug.jpg” which exists in my main bundle):NSData *imgData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@", [[people objectAtIndex:user] uImage]]];
UIImage *diasplayImage = [UIImage imageWithData:imgData];
uImage.image = diasplayImage;I couldn’t figure out why it didn’t work, until I read more of the documentation. the dataWithContentsOfFile method in NSData expects an absolute path to the image. As soon as I gave it “/Users/me/absolute/path/to/mug.jpg” it worked like a charm. I’m going to have to learn more about the iPhone filesystem, but for this app, loading an image this way isn’t really what I want. I’d rather just grab the image relative to my main bundle. I do this like so:
uImage.image = [UIImage imageNamed:[NSString stringWithFormat:@"%@",[[people objectAtIndex:user] uImage]]];imageNamed looks first in the cache for the image. If it doesn’t find it there it will look in my main bundle, cache it, then display it.
- Don’t forget to link the UIImageView object (in the nib) to my “File’s Owner” uImage outlet.
- I’m using the tag property of each button in my PersonListViewController to tell my PersonDetailViewController which button was pressed (which user was selected)