Tuesday, April 21, 2009

Navigation Controller Fun

Add 2 (plus 2 headers automatically added) to your Classes group.  Nav1ViewController and Nav2ViewController, both using the template of UIViewController subclass.

Drag a Navigation Controller over from the toolbox and drop it onto the Tab Bar Controller.  Take a Tab Bar Item and do the same thing. Run it.  I think it "just works" and shows a new view with a navigation controller on the third tab.  

Add 2 new Nibs, from View Nib, called NavView1 and NavView2.  Set their File's Owner's class appropriately.  Associate the View Outlet with the view.  Run it.

Now, add a button to the NavView1.xib.  Go to your Nav1ViewController.h file.  Put in this line: 
-(IBAction)LoadNextPane:(id)sender; after the end of he Interface block, before the @end block.

Put this code in the .m file:
// Do something
UIViewController *targetViewController;
targetViewController = [[SecondViewController alloc] initWithNibName:@"NavView2" bundle:nil];
[[self navigationController] pushViewController:targetViewController animated:YES];


At the top of the .m file, you must include an import to the file that tells the compiler about what SecondViewController really is.

#import "SecondViewController.h".

Now we have an action (I think of it as an event, but it probably isn't).  Go back to the NavView1.xib file.

Associate your button's "Touch Up Inside" to the File's Owner, and choose the "LoadNextPane" option.  It's the only one that should appear.  Run it.  Kaboom.  Not sure why right now.

The problem was that I had not, in MainWindow.xib set the Nav1 View Controller (Navigation Item) 's class to Nav1ViewController.  Once I did that, the 2nd nav view scrolled on screen with the button push.

iPhone -- Interface Builder, Part 2

See iPhone -- Interface Builder, Part 1 for instructions to get to this point.

So, let's make SecondView use a code file.  Right click on Classes and choose "New File".  On the left of the New File window, under iPhone OS, choose Cocoa Touch Class, and on the right, choose UIVIewController subclass.  Click Next, give it a name of SecondViewController.m and his Finish.  It made the .h for you, automatically.  Build and Run still works, but we really haven't done anything.

Open your SecondView.XIB and change its class to SecondViewController.  It still builds and runs.  Okay...so what have we allowed ourselves to do?  Well, I THINK that we can now override things on the second view, respond to events, set items on it, etc.  So, we have a code file instead of just a dumb view with text on it.

Now, let's get FirstView.xib built.  Right click on "Resources", add new file, choose User Interfaces, and choose View XIB.  A part of me really really really wanted to be able to choose "View Controller XIB" but alas, that is not an option.  Give it a name of FirstView.xib.  Change the File's Owner class to FirstViewController.  Set the File's Owner's "view" outlet to the view that was created.  Add a label to the view so we know it is OUR view, and not the default one they made.  Go back to MainWindow.xib, and set the "Selected First View Control" to load from NIB FirstView.  Finally, delete the View tree under "Selected First View Controller".

Build and run, and you should see YOUR first view already loaded.

Also, go back to MainWindow.xib and change the "Second View Controller"'s class to "SecondViewController".  Not sure if that makes a difference, but I think it does.

iPhone -- Interface Builder, Part 1

Interface Builder is currently the bane of my existence.  I just don't quite understand what I'm doing, and I definitely don't understand HOW it is working.  I'll outline the latest project here, and how I sort of got it working.  I mean, I DID get it working, but I'm not sure about some of the decisions I made and how it will bite me down the road.

I started out by creating a Tab Bar Application based project in Xcode.  I ran it, and it compiled.  Check.  The MainWindow.xib file already has the first view loaded into it, but the 2nd is done via magic.  I wanted to figure out what the magic really was.  The "First View" has this text in a label:  "Optionally move this view into a separate nib file and set the nib name in the First View Controller Attributes."  Well, why not try this?  Let's see if I can replicate this as I type, mistakes and all.

First, I looked at the inspector for the MainWindow.xib file.  File Owner is a class of "UIApplication".  It also has an entry called "App Delegate", and it's class is "TBNB001AppDelegate"  This is the name of my application (TBNB001), and when I made the project, Xcode created TBNB001AppDelegate.h and .m for me automatically.  This is what is assigned to the "App Delegate".  

MianWindow.xib has a Window, but that is pretty uninteresting, I think, because I believe that all iPhone apps need to have 1 window, and that's all.  It's a class of UIWindow, so it hasn't been altered or overridden, etc.

Then we get to the last parent level object, "Tab Bar Controller".  It's type is UITabBarController, but it isn't listed in the Inspector.  That's...odd.  Why?  I mean, I don't plan on overriding or catching any events from the Tab Bar (actually, I do later on, but that is my project specific, and I'll deal with that later).  But shouldn't it have a class of UITabBarController, too?

Under "Tab Bar Controller" is "Tab Bar".  Okay...same thing as the Controller above...it has a type, but no specified Class.  I HAVE to assume here that if the Class is blank, then it is just the same as putting in the default class.

Next under "Tab Bar Controller" is "Selected First View Controller".  Not sure if "Selected" is set from some property I couldn't find, or if it was just called that.  No idea.  It's class is called FirstViewController -- again, this relates to 2 files of the same name + .h and .m that Xcode created for me automatically.  The View Controller has a connection to the view inside of it.  A View Controller must have a default Outlet defined for a view, cause it sure isn't anywhere in the code for "FirstViewController.h" or .m.

Now, look at the structure for "View Controller (Second)"  It's class and type are both UIViewController.  VC1 has a view outlet that is used, but VC2's view is unassigned.  On the last page of the inspector, VC1 has no class outlets defined, but VC2 does, and it is a UIView.

I'm pretty confused, I have to say.

Finally, though, VC2 is set to load from a NIB called "SecondView".  Ahh, that magic part, I guess.  So, I do have another file, and it is called SecondView.xib.  I don't have one for the first, but I do for the second.  The first is defined in place in the MainWindow.xib file, under the Tab Bar Controller -> Selected First View Controller structure.  The Second View Controller doesn't have that, because it gets loaded from an external .NIB.

Now, for "SecondView.xib".  It's File Owner's class is UIViewController.  It has an outlet defined, and it is associated to the View in the file.  All of this was done for us already. 

SecondView doesn't have a set of associated code files.  Well, I really like to do things in code because it usually ends up being more flexible later on, plus I find it helps me figure out WHY things work the way they do.