Showing posts with label apple. Show all posts
Showing posts with label apple. Show all posts

Monday, April 20, 2009

iPhone tutorial: "Tab Bar Application" part 2

In the last post I mentioned that I would probably write a short post commenting on the source of the XCode "Tab Bar Application" template. There really isn't that much to say about the source since there is very little of it - almost everything we see when running the app happens because of the objects in the xib files.

Let's take a look at one thing though. Go to XCode and select Classes/Tab1AppDelegate.m. Scroll down to the method 'didSelectViewController' and un-comment it. Edit the source so that the body of the method looks like this:


NSLog([NSString stringWithFormat:@"didSelectViewController:%@", viewController.title]);

Run the program by pressing CMD-Return and after the iPhone simulator window appears, select the XCode window and press CMD-R to bring the debugger window to the front. We do this, since this is where the text produced by NSLog() appears.

didSelectViewController is part of the UITabBarControllerDelegate protocol so we can expect the tab bar to "send this message" to us, that is, call this method when we press one of the buttons on the tab bar. Let's try that. Yes, go ahead and press the tab bar buttons in the simulator and see what happens. Did you remember to press CMD-R in XCode to bring the debugger window to the front by the way? If not, do it now.

Ok, so what happened? Not much, huh? Have we found a bug in the iPhone API or why isn't the method called? No, it's not a bug in the iPhone API but maybe in the XCode template application. Or more specifically in MainWindow.xib. To resolve the problem/bug, double-click on Resources/MainWindow.xib to start Interface Builder (IB). In IB go to the MainWindow.xib file and select "Tab Bar Controller" and press CMD-2. See that it has a 'delegate' outlet which isn't connected to anything? That's probably the explanation to the problem. Let's connect it to "Tab1 App Delegate" and see if that works better.

Remember that you have to "think backwards" (atleast in my view) to connect an outlet by CTRL-dragging in IB? Ok, start by positioning the mouse over "Tab Bar Controller". After that press and hold CTRL while you drag the mouse until it's positioned over "Tab1 App Delegate". Now release the mouse and a window should pop up. In that window, click on 'delegate'. This should have connected the 'delegate' outlet of "Tab Bar Controller". To verify this, select "Tab Bar Controller" and press CMD-2. A connection now exists to "Tab1 App Delegate", right? If not, try again! When you have succeeded, save the IB file (CMD-S).

Return to XCode and build and run (CMD-Return). Wait for iPhone Sim to start up and then select the source window in XCode again and bring up the debugger window (CMD-R).  Play around in the simulator a bit by pressing the two buttons and you should see something like this in the debugger window:

2009-04-20 22:40:14.842 Tab2[5188:20b] didSelectViewController:First 2

2009-04-20 22:40:19.972 Tab2[5188:20b] didSelectViewController:(null)

2009-04-20 22:40:22.026 Tab2[5188:20b] didSelectViewController:First 2

2009-04-20 22:40:23.227 Tab2[5188:20b] didSelectViewController:(null)

2009-04-20 22:40:24.506 Tab2[5188:20b] didSelectViewController:First 2

2009-04-20 22:40:25.746 Tab2[5188:20b] didSelectViewController:(null)

2009-04-20 22:40:27.139 Tab2[5188:20b] didSelectViewController:First 2


Wow, it works! But why do we get a "(null)" title for one of the view controllers? The second one to be specific. Go back to IB and select "First View Controller" in MainWindow.xib and press CMD-1. See that the 'title' is set to "First 2"? That's because it was set to that name in the "View Controllers" table in the "Tab Bar Controller" object in XCode (select it and press CMD-1 to verify). However, if you select the second view controller in MainWindow.xib - the one called "View Controller (Second)" and press CMD-1, you'll see that the title here is empty even though it had a name in the view controllers table in "Tab Bar Controller".

This probably has to do with the fact that the second view controller is defined in and loaded from another xib-file - Resources/SecondView.xib - but I'm not completely sure. To remedy this and set the title, select "View Controller (Second)", press CMD-1 and edit the title. Save the xib file (CMD-1) and return to XCode and build and run (CMD-R) and you'll see that it works.


Sunday, April 19, 2009

iPhone tutorial: Analysing XCode's "Tab Bar Application" template

If you've read the previous posts you probably know where to start, but here comes a brief procedure: Start XCode, choose "File/New project" from the menu, select the "Tab Bar Application" icon and name the project "Tab1". After XCode has created the project for you, expand the "Classes" and "Reosources" groups in XCode's "Groups and files" frame, you'll see that this template contains the following:

Tab1
  Classes
    FirstViewController.[hm]
    Tab1AppDelegate.[hm]
  Resources
    SecondView.xib
    MainWindow.xib
    Info.plist

To get a quick overview of what the application does, build and run it in XCode by pressing CMD-Return. The iPhone simulator should pop up and you should see a white background with the text "First View" on it. Below that is a block of text and at the bottom of the screen there are two grey-blackish buttons labeled "First" and "Second". If you press the button called "Second" you are presented with another white background, but this time with the text "Second View" on it. It also has a block of text and the two buttons labeled "First" and "Second" at the bottom.

The buttons at the bottom of the two screens are implemeted by using a "tab bar controller" (UITabBarController) which is used to easily switch between a number of  full screen views. In this context, full screen means the area above the buttons at the bottom, because the tab bar has reserved the bottom part of the screen for itself. If it didn't do this, it would be pretty hard to switch to another view since its button/tab would be obscured by the contents of the view.

After familiarising ourselves with the application we can do the following guesses about the files in project: Tab1AppDelegate.[hm] is the class implementing the UIApplicationDelegate protocol, FirstViewController.[hm] is probably used for implementing the view which had the text "First View" written all over it, MainWindow.xib is the IB file loaded automatically at start up (double check the "Main nib file base name" property in Info.plist to verify this) and SecondView.xib is the IB file describing how the second view should look like.

All this sounds logical, but some things seem a bit odd. Why isn't there a FirstView.xib file and no SecondViewController.[hm] files? We'll have to start digging to understand that and let's start with the h-files. 

Classes/Tab1AppDelegate.h

@interface Tab2AppDelegate : NSObject {


This class implements two protocols, the usual UIApplicationDelegate and a new acquaintance called UITabBarControllerDelegate. An educated guess whould be that the new protocol is used for "receiving messages" from a UITabBarController.


    UIWindow *window;

    UITabBarController *tabBarController;

}


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

@property (nonatomic, retain) IBOutlet UITabBarController *tabBarController;


We have pointers to an UIWindow and an UITabBarController which we want to be externally accessible as well as being manipulated by Interface Builder (IB). Therefore we declare the pointers as properties as well as mark them with IBOutlet.

Classes/FirstViewController.h

Nothing exciting, it just declares that it is a subclass of UIViewController.

Resources/MainWindow.xib

Double-click it to bring up IB and immediately switch view mode in the MainWindow.xib window which appears in IB by selecting the middle button above the "View mode" text in the upper left corner of the window. This is the hierarchical view which you can explore by pressing the small arrows to the left of the objects to see the full hierarchy of objects in this xib-file. Press all the arrows you can find to fully expand the list into this:

File's owner [UIApplication]
First Responder [UIResponder]
Tab1 App Delegate [Tab1AppDelegate]
Window [UIWindow]
Tab Bar Controller [UITabBarController]
  Tab Bar [UITabBar]
  Selected First View Controller [FirstViewController]
    View [UIView]
      Label (First View) [UILabel]
      Text View [UITextView]
    Tab Bar Item (First) [UITabBarItem]
  View Controller (Second) [UIViewController]
    Tab Bar Item (Second) [UITabBarItem]

This view mode in IB is so much better than the default which only shows the top level objects as big icons! In this view you can see all the objects in the file and even their classes, which is great for quickly understanding what we're working with. If this view also had shown all the connections between the objects we would have known almost everything about the file...

Hmm, there actually is a way to see the connections. Not all at once which would have been really neat, but you can at least see them. Position the mouse pointer over the object (row) in the table you want to examine  and CTRL-click a window will pop up which shows all the connections (outlets and referencing outlets). You have to close this window manually so if you repeat the procedure for all objects you can actually see all the connections at once, even though there will be a lot of windows on your screen! ;)

Before starting to dig, let's play a little! You probably noticed that IB opened another window besides the MainWindow.xib window, namely a big iPhone-sized window displaying the text "First View" in a quite large font. Yep, that's the contents of this xib displayed graphically, that is, how the objects will be layed out (positioned) in the iPhone when we run the application. This is not a full simulation of the interface, but rather an "edit view" of the interface where we can manipulate the objects instead of just interact with them. Interaction is possible here too though as you can experience by pressing the "Second" button at the bottom of the window.

Something happened, right? But maybe not exactly what you expected? Instead of seeing a big bold text saying "Second View" as we did when we test ran the application in the simulator from XCode we see a rather modest text saying: View. Loaded from "SecondView.nib". When you pressed the "Second button" something less obvious also happened. What I'm talking about becomes visible if you activate the MainWindow.xib window. At the end of the list of objects in this window is the object "Selected View Controller (Second)".

Really observant readers might remember that in the "full hierarchy" list above there was no "Selected" text before this object's name. However, there was a "Selcted" before the "First View Controller (First)" object's name, which it no longer is. This "Selected" text thus indicates which view controller we currently have selected in the edit window. Press the "First" button and after that activate the MainWindow.xib window and you'll see that the "Selcted" text has been moved back to its original position. (The fact that you have to activate the MainWindow.xib window to see this change seems like a bug in IB.)

Speaking of the MainWindow.xib window. As you can see, some object names also contains some text within parentheses, like "First View Controller (First)" and "Label (First View)". The text within parentheses represent the "identifying" value of an object. A label is used to display a short text and thus the "text" property is shown. You can verify this by double clicking on the "First View" text in the edit window and change the text. After pressing return, the new text will be visible within parentheses in the MainWindow.xib window.

So where does the text "(First)" in "First View Controller (First)" come from and which property of a view controller does IB consider to be the "identifying" since it is displaying it here? That we'll find out when we start examining all the objects in detail, which we'll do right now!

Resources/MainWindow.xib

File's owner

CMD-4 shows us that the class is UIApplication (which we already knew since we're using the hierarchical view mode in the MainWindow.xib window) and CMD-2 shows us that the 'delegate' property is set to 'Tab1 App Delegate' (which we also can see by CTRL-clicking on the object in the MainWindow.xib window). This seems logicaly since we in the beginning of this post saw that Tab1AppDelegate.h declared that Tab1AppDelegate.m implements the UIApplicationDelegate protocol.

First Responder

Nothing exciting.

Tab1 App Delegate

CMD-4 gives us the class "Tab1AppDelegate" and the outlets 'tabBarController' of class UITabBarController and 'window' of class UIWindow just like we declared in Tab1AppDelegate.h. CMD-2 shows that 'tabBarController' is connected to an object named "Tab Bar Controller" and 'window' is connected to an object named "Window", both of which you can see in the hierarchical view of the MainWindow.xib window.

Window

CMD-4 says it's an UIWindow (surprise!) and CMD-2 says that the 'window' property of the "Tab1 App Delegate" object has been connected to this window.

Tab Bar Controller

CMD-4 says it's a UITabBarController and that it has an outlet called 'delegate', which probably means that this object is going to send messages to (call methods of) another object. Guessing some more, the receiving object should probably implement the UITabBarControllerDelegate protocol, just like we saw in Tab1AppDelegate.h. CMD-2 however shows that the 'delegate' outlet is unconnected - how disappointing! We'll have to examine that further in a while...

CMD-1 (attributes) shows the most exciting part of this object - a table called "View Controllers" with two columns "Title" and "Class". A tab bar controller controls a set of view controllers and this table specifies which objects that represent the view controllers.

If you want to read more about this right now I suggest that you check out the API docs for UITabBarController. This is easiest done by going to XCode, select the file Tab1AppDelegate.h, select the text UITabBarController in the interface definition and CTRL-click on the selected text. This should pop up a window where you can select "Find Selected Text in API Reference". This should bring up a new window with some search result in the upper half and text in the lower half. To the left there is a table of contents section where you should find the section "Properties". Expand that and you should see a property called 'viewControllers' - that's the property we are manipulating in the table in IB.

Ok, back to the "View Controllers" table in IB. Double-click on the Title-column in the first table row, right where it says "First". Edit the text to say "First 2" or something similar. Notice how the "(First)" text was changed to "(First 2)" in the MainWindow.xib window for the "First View Controller"? So this is where the "(First)" text came from - it's the view controller's title. If you return to the edit window, you'll see that this is the text presented on the button at the bottom of the screen, which selects this view controller.

Now try pressing the plus-sign ('+') just below the table. A new row should appear in the table and if you check the MainWindow.xib window you should notice that a new view controller and associated "Tab Bar Item" should have appeared at the end of the list. Then check the edit window to see that a new button also should have appeared. This is how easy it is to add a view controller to a tab bar controller. Remove the third controller we just created by selecting it in the table and pressing the minus-sign ('-') under the table or press backspace.

Tab Bar

This is more or less an "internal" object of the tab bar controller which we shouldn't mess with in IB, or anywhere really. This is what the API docs for UITabBarController says about it: 

"Although a tab bar controller uses a tab bar in its implementation, you should never need to, nor should you, access the tab bar directly."

First View Controller (First 2)
CMD-4 says it is of the class "FirstViewController", which is one of our classes - go check in XCode if you had forgotten about it. No outlets are shown here, but since it's a subclass of UIViewController (check the h-file in XCode) it of course has the standard outlets of a UIViewController. This can be seen in CMD-2 where we see that one of the standard outlets, 'tabBarController' is connected to an object called "Tab Bar Item (First)" and 'view' is connected to an object called "View". Both these are explained below, while the 'tabBarItem' is best understood by reading the API docs for UIViewController, especially the section about the 'tabBarItem' property. Basically, this property is used to defined how this view controller should be represented on a tab bar, that is what its "button" will look like.

CMD-1 gives the title as "First 2" - hey, that's what we changed it to in the "View Controllers" table in the "Tab Bar Controller" object a short while ago. The "NIB Name" is empty, but we'll soon see an example where it isn't - exciting, huh?

View

Neither CMD-4 or CMD-2 show anything surprising - it's a simple UIView.

Label (First View)

Neither CMD-4 or CMD-2 show anything surprising - it's a simple UILabel. CMD-1 on the other hand shows that the text-property is set to "First View" which is exactly the same as the text we saw when we test ran the application in XCode or look at the edit window here in IB. It's the text that the label should display - as simple as that!

Text View

Neither CMD-4 or CMD-2 show anything surprising - it's a simple UITextView. A bit more surprising is that CMD-1 doesn't show anything special either, so how did the text get into the view? Well, it's as simple as double-clicking the text view in the edit window and type what you want it to display. IB ensures that the text finally ends up in the UITextView's text-property.

Tab Bar Item (First 2)

CMD-4 and CMD-2 are both unexciting. CMD-1 says that the title is 'First 2' - here we go again. It seems as if the text we entered in the "View Controllers" table of the tab bar controller affected a couple of objects - first the view controller's title and now this. Read more about tab bar items by searching for UITabBarItem in the API docs in XCode.

View Controller (Second)

Ok, now the tricky part of this tutorial starts so keep focused. Remebered that the "second view" looked a bit strange when we switched to it in the edit window in IB? It said something about that this view was loaded from a nib. Double click on the "View Controller (Second)" row in the MainWindow.xib window and we'll see exactly what it said since this pops up the edit window. There we go: Loaded from "SecondView.nib".

If you take a look in the MainWindow.xib window you'll see another strange thing. The branch of the object hierarchy starting with "First View Controller" has lots of objects under it - View, Label, TextView, TabBarItem - while the branch starting at "Second View Controller" just has a TabBarItem. This is strange since the first and second views looked more or less identical - both had a title and some text. It turns out the View, Label and TextView items for this view are loaded from a another IB-file, "SecondView.xib" to be specific.

This is pretty cool. Instead of defining "everything" in a single IB file you can modularise your interface design into several IB files and then refer to them from a main IB file or similar. For a tab bar controller interface, this is very nice.

So how does this magic happen? Lets explore the object and see if we can find out. CMD-4 shows nothing special - it's an UIViewController with the standard outlets. CMD-2 shows that one of its outlets, 'tabBarItem', is connected to an object called "Tab Bar Item (Second)". It's also worth noting that the 'view' outlet isn't connected to anything. This is different from how it was in "First View Controller" (see above) and will therefore be explained shortly.

Tab Bar Item (Second)

This is the tab bar item for the second view controller. It is defined in the same way as the item for the first view controller. It's worth noting that it is defined here in MainWindow.xib and not in SecondView.xib though. The reason for that is that it "belongs to" the tab bar controller and tab bar which are defined in this IB file.

Resources/SecondView.xib

File's owner

You have remembered to switch the SecondView.xib window view mode to the hierarchical view mode (middle button above the text "View Mode"), right? Good, this should be made into a habit. All the "File's owner" object we have examined so far have been pretty boring, but this one actually is a bit interesting. Why? Press CMD-4 and you'll see that the class is "UIViewController". Interesting, can a view controller own (use) an IB-file? Well, apparently... Which view controller is it then? Well, it's "View Controller (Second)" in MainWindow.xib since we specified in the attributes window (CMD-1) that it should use an IB file called "SecondView". Sorry, no magic here either, just plain old logic.

Ok, did you really understand what was written above? That the "File's owner" object in this IB file is of the class UIViewController? You did? Good, let's continue then. As you know by now, UIViewControllers has three standard outlets (CMD-4 to see them). CMD-2 shows that the 'view' property of this view controller is set to an object called "View" which exists in this IB file.

What does it actually mean to set the 'view' property of the "File's owner" object? It means that we will set the 'view' property of the object which "loads" this IB-file and use it to initialise itself. In our case that is the "View Controller (Second)" object in MainWindow.xib. If you have a keen memory you will remember that we said it was a bit strange that that view controller did'nt have its 'view' property set (see above) and that we would explain that later. Well, later is now, and this is how it is set. Pretty neat, right?

The remaining objects in this IB-file are more or less identical to the corresponding objects under the "First View Controller" branch in MainWindow.xib so I won't bore you with the details here.

That's it for now. I'll probably write a short post explaining some things in the source code for this template too, but this post focused on the Interface Builder stuff...


Sunday, April 12, 2009

Tutorial: Analysing XCode's "Utility Application" iPhone-template source code

In the last post, we looked at XCode's "Utility Application" template mainly in Interface Builder (IB), but this time we will take a better look at the actual source code in XCode. So either start a new "Utility Application" project named "Util1" or load the "Util1" project we created in the last post.

We did look at some source in the last post and noticed that MainView.[hm], MainViewController.[hm], FlipsideView.[hm] and FlipsideViewController.[hm] all are "almost empty" or at least very unexciting. We also looked at Util1AppDelegate.[hm] and RootViewController.h in the last post, so that more or less leaves RootViewController.m for this post.

Application Controllers/RootViewController.m

- (void)viewDidLoad {
[super viewDidLoad];
MainViewController *viewController = [[MainViewController alloc] initWithNibName:@"MainView" bundle:nil];
self.mainViewController = viewController;
[viewController release];
[self.view insertSubview:mainViewController.view belowSubview:infoButton];
}


RootViewController is a UIViewController which implements a method called 'viewDidLoad'. This methods gets called when a UIViewController object is created from a nib file, or actually after its 'view' is set. Here we override that method so that we also can get a chance to manipulate the newly created RootViewController object.

The first thing we do is to call the viewDidLoad method in our super class (UIViewController) to take advantage of the initialisations it does. After that we allocate an object of class MainViewController and initialise it from a nib file called 'MainView' which is our Resources/MainView.xib file. That newly allocated MainViewController object is temporarily stored in a local pointer called 'viewController' and permanently stored in this object's property 'mainViewController'. After that we release our reference to the MainViewController object using the temporary variable. This is done because the 'mainViewController' property was flagged with the 'retain' keyword in RootViewController.h.

Finally, we insert the view of the MainViewController object we just read from MainView.xib below the 'infoButton'. We insert it below so that the 'infoButton' still will be visible - otherwise it could be blocked by the main view. The reason for why you see no code which sets up the view of 'mainViewController' or the 'infoButton' is that all that is done automatically when the xib files are read. Ok, we actually did the work ourselves in Interface Builder (IB), so the magic part is that we don't have to write any Objective-C source code for it - instead we did some CTRL-dragging in IB.

Ok, so when we implement the 'viewDidLoad' method we get the chance to do additions or changes to the UIViewController object which was read from a xib file. The reason for why we didn't do everything in IB is that some things are impossible to do in IB and others are just simpler to do in source code.

After this, we have a RootViewController object in memory. Two of it's properties have been set; 'infoButton' was set in IB and 'mainViewController' was set in the 'viewDidLoad' method above. 'flipsideViewController' and 'flipsideNavigationBar' are still unset. We'll wait with those a while and instead take a look at our 'toggleView' action, which is implemented in the method 'toggleView'!


- (IBAction)toggleView {
/*
This method is called when the info or Done button is pressed.
It flips the displayed view from the main view to the flipside view and vice-versa.
*/

Ok, this nice comment pretty well explains what this method does.


if (flipsideViewController == nil) {
[self loadFlipsideViewController];
}

Here we check if the 'flipsideViewController' property is set and if it isn't we call the 'loadFlipsideViewController' method which hopefully sets the property for us.


UIView *mainView = mainViewController.view;
UIView *flipsideView = flipsideViewController.view;


We get the view properties from our the two UIViewControllers that are involved in the flipping action - "main view" and "flipside view" and store them in two local pointers.


[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1];
[UIView setAnimationTransition:([mainView superview] ? UIViewAnimationTransitionFlipFromRight : UIViewAnimationTransitionFlipFromLeft) forView:self.view cache:YES];

Help! What on Earth is this? Well, it's actually one of the coolest features of the iPhone API since it allows you to easily implement all those incredibly cool graphical effects you see when you play around with your iPhone - for example flipping a screen over so you can look at the "back" of the screen. In iPhone language these effects are called "animations" since they, instead of making something happen immediately, make something happen smoothly over time, that is, animating it...

Animations change something from an initial state to a final state. The initial state often is the current state so often it's enough to describe the final state. Since you might want to animate a lot of "things" at once you have to describe them at once so that one thing doesn't start animating (moving) before another. Therefore, you start an "animation block" by calling 'beginAnimations' in the UIView class. Each animation block also has a time over which the animation will happen, specified by calling 'setAnimationDuration' with a number of seconds as an argument (this is a float, so 0.1, 1, 1.5, etc. are all valid values.) You can also specify how you want to animate; that is what "graphical effect" we want to use. Here we either want to flip from the right or from the left depending if we're moving from the main view to the flipside view or vice versa.

The line specifying "from right" or "from left" might be worth explaining. How do we decide if we're flipping from the "main view" or the "flipside view"? We check if the "main view" has a superview! If it does, it's the main view that is visible and we're flipping from the right. How did it get a superview? Remember the 'viewDidLoad' method we implemented above? In that we "inserted" the "main view" into the "root view" and thus the "main view" got its superview.


if ([mainView superview] != nil) {
[flipsideViewController viewWillAppear:YES];
[mainViewController viewWillDisappear:YES];
[mainView removeFromSuperview];
[infoButton removeFromSuperview];
[self.view addSubview:flipsideView];
[self.view insertSubview:flipsideNavigationBar aboveSubview:flipsideView];
[mainViewController viewDidDisappear:YES];
[flipsideViewController viewDidAppear:YES];

} else {
[mainViewController viewWillAppear:YES];
[flipsideViewController viewWillDisappear:YES];
[flipsideView removeFromSuperview];
[flipsideNavigationBar removeFromSuperview];
[self.view addSubview:mainView];
[self.view insertSubview:infoButton aboveSubview:mainViewController.view];
[flipsideViewController viewDidDisappear:YES];
[mainViewController viewDidAppear:YES];
}

In this fat block, we continue to set up the "final state" of our animation. Here too, we care about if we're animating from the "main view" to the "flipside view" or vice versa. As you can see(!) the code is almost self-explanatory thanks to the rather well chosen names of all the methods we call and all the objects we work with. What we basically do is removing everything that is associated with the view we are "flipping out" and adding everything associated with the view we're "flipping in".


[UIView commitAnimations];
}

This ends our animation block and actually commits the animations we described for execution. Exactly when they will happen is outside our control, but you can trust the iPhone to do its best to make it look good ;)

Ok, we still haven't seen how the 'flipsideViewController' and 'flipsideNavigationBar' properties of our RootViewController object gets set so let's take a look at the 'loadFlipsideViewController' method which is said to solve that problem for us.


- (void)loadFlipsideViewController {

FlipsideViewController *viewController = [[FlipsideViewController alloc] initWithNibName:@"FlipsideView" bundle:nil];
self.flipsideViewController = viewController;
[viewController release];

This is pretty similar to what we saw for the "main view" in the 'viewDidLoad' method. Allocate the object and initialise it using a nib file, in this case a FlipsideViewController from Resources/FlipsideView.xib.


// Set up the navigation bar
UINavigationBar *aNavigationBar = [[UINavigationBar alloc] initWithFrame:CGRectMake(0.0, 0.0, 320.0, 44.0)];
aNavigationBar.barStyle = UIBarStyleBlackOpaque;
self.flipsideNavigationBar = aNavigationBar;
[aNavigationBar release];

Cool, here we're creating a UINavigationBar programmatically (in source code) and store a reference to it in the 'flipsideNavigationBar' property of our RootViewController.


UIBarButtonItem *buttonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(toggleView)];

Add the "Done"-button and make it call 'toggleView' when pressed.


UINavigationItem *navigationItem = [[UINavigationItem alloc] initWithTitle:@"Util1"];

Create the "title".


navigationItem.rightBarButtonItem = buttonItem;
[flipsideNavigationBar pushNavigationItem:navigationItem animated:NO];
[navigationItem release];
[buttonItem release];
}

And close the case!

That's pretty much it! It took an impressive amount of words to explain this little application, but hopefully it has helped your understanding of the Interface Builder, the iPhone API and how to "think" when creating iPhone applications. A fine tuned mix of source code and "pre-packed" objects created with Interface Builder is often the right way to go even though everything, of course, can done programmatically - completely in source code.

Friday, April 10, 2009

Tutorial: Analysing XCode's "Utility Application" iPhone-template in Interface Builder

In the last two posts we analysed XCode's "Window-Based Application" template, with an emphasis on understanding how to use Interface Builder (IB) during iPhone application development. That template is a good starting point, since it's very simply but yet makes rather good use of IB.


Now, we'll move onto something more exciting by analysing XCode's "Utility Application" template, so start up XCode, choose  "File/New Project" from the menu and select the Utility Application project and name it Util1. This is a quite interesting project, since it has multiple classes, multiple xib-files and even some user interaction via a GUI button. Lets start by looking at the file structure in XCode:


Util1

  Main View

    MainView.[hm]

    MainViewController.[hm]

  Flipside View

    FlipsideView.[hm]

    FlipsideViewController.[hm]

  Application Controllers

    RootViewController.[hm]

    Util1AppDelegate.[hm]

  Resources

    FlipSideView.xib

    MainView.xib

    MainWindow.xib

    Info.plist


Ok, it seems as if there are six classes (MainView, MainViewController, FlipsideView, FlipsideViewController, RootViewController and Util1AppDelegate). and three xib-files (FlipsideView, MainView and MainWindow). The things we recongnize from before are Util1AppDelegate, MainWindow.xib and Info.plist.


Before we dive into the details, build and run the project by pressing CMD-Return to see what it does! A grey background with a small icon in the lower right corner should appear. The small icon has a lowercase "i" in it, which in iPhone language means that it is an "info-button". Press it and see what happens!


Wow, it triggered a really nice graphical effect which "flipped" the grey screen away and flipped in a black screen with some kind of title bar containing the text "Util1" and a "Done"-button at the top of the screen. Let's press the "Done-button" and see what happens.


Cool, it flipped back to the original grey screen again! Ok, as you can see, this is a very nice application which probably would make anyone you showed it to drool in envy and bow in respect to you if you said that it was you who have made it!


After watching this fantastic presentation we understand why some of the files have names with the word "Flipside" in them - they probably have something to do with the stuff that was "flipped in" when we pressed the info-button on the main screen. Hey, there is a main screen also? Ok, now we understand why some files have the word "Main" in their names!  This flipping effect is actually designed to make it look like you can look at the backside of your main screen - almost like flipping your iPhone around in order to admire the beautiful Apple-logo ;)


Ok, enough talk, let's start wading through the files.


Examining the source files


Resources/Info.plist


Double-click it and you'll see that "Main nib file base name" is set to MainWindow, which means that Resources/MainWindow.xib will be loaded automatically when starting the application.


Before we start analysing the xib-file, we'll take a look at the classes, because otherwise it might be a bit hard understanding the objects and connectionsin the xib-file.


Application Controllers/Util1AppDelegate.h


@interface Util1AppDelegate : NSObject <UIApplicationDelegate> {


Ok, this is the object implementing the UIApplicationDelegate protocol...


    UIWindow *window;


and it has a window...


    RootViewController *rootViewController;


and something called a RootViewController. If you look in the file list in XCode, you'll see that this is one of the classes in our project so we'll dive into that one soon.


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


We want to manipulate our GUI objects from IB so we declare accessor methods for 'window' and also tag it with IBOutlet so that IB will discover it.


@property (nonatomic, retain) IBOutlet RootViewController *rootViewController;


The same goes for the mystical 'rootViewController'.


Application Controllers/Util1AppDelegate.m


- (void)applicationDidFinishLaunching:(UIApplication *)application {


We want to do something when the application has finished launching so we implement the appropriate method from the UIApplicationDelegate protocol.

    

    [window addSubview:[rootViewController view]];


The mystical rootViewController has a reference to a UIView object, accessible by calling it's 'view' method. We want to add this view to our window in order to display it, which is accomplished by calling 'addSubView' on our UIWindow 'window'


    [window makeKeyAndVisible];


Calling makeKeyAndVisible on a UIWindow makes it visible as well as making it the "first responder" of events (touches).


Application Controllers/RootViewController.h


@interface RootViewController : UIViewController {


The mystical class RootViewController turns out to be a subclass of UIViewController. A UIViewController is primarly used if you have a full screen view, which we do, and using it instead of just a view has a couple of benefits, but we won't go into that now.


    UIButton *infoButton;

    MainViewController *mainViewController;

    FlipsideViewController *flipsideViewController;

    UINavigationBar *flipsideNavigationBar;


We have an UIButton called 'infoButton', two other view controllers and a navigation bar. Judging by their names the view controllers are used for the main screen and the flipside screen we saw when we tested the application.


}


@property (nonatomic, retain) IBOutlet UIButton *infoButton;

@property (nonatomic, retain) MainViewController *mainViewController;

@property (nonatomic, retain) UINavigationBar *flipsideNavigationBar;

@property (nonatomic, retain) FlipsideViewController *flipsideViewController;


We want all of our properties to be accessible by other classes so we declare them as properties, but we only mark 'infoButton' with IBOutlet so apparently that's the only thing we will manipulate from IB.


- (IBAction)toggleView;


IBAction instead of IBOutlet - that's something new! You'll have to read the full post before understanding this one, so for now you can ignore it.


Main View/MainViewController.h

Flipside View/FlipsideViewController.h


Both these just declare that they are subclasses of UIViewController.


MainView/MainView.h

FlipsideView/FlipsideView.h


Both these just declare that they are subclasses of UIView.


MainView/MainView.m

FlipsideView/FlipsideView.m


Both these are quite unexciting, but the following might be worth explaining


- (id)initWithFrame:(CGRect)frame {


Initialising this view is done by passing it a CGRect which defines a rectangle called 'frame', which will be used to set the size of the view. The return type is 'id' since we will return an object - a MainView or FlipsideView object to be precise.


    if (self = [super initWithFrame:frame]) {


The CGRect 'frame' is immediately passed to it's superclass UIView to take advantage of the initialisation it already provides. If the UIView initialisation worked we'll get a non-null pointer to an UIView in 'self' - that's "us".


    return self;


Here we return a pointer to "ourselves" so our caller can use the object we now have successfully initialised.


Main View/MainViewController.m


- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {


Creating a MainViewController object will apparently be done by providing a nib (IB-file).


    if (self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]) {


This nib is directly passed on to our superclass UIViewController to let that handle the initialisation.


Flipside View/FlipSideViewController.m


This class has no "init"-method like MainViewController. Instead it has a method called viewDidLoad. This method is implemented in UIViewController (our superclass) and we should override it, as we do here, if we want to change something after our view has been loaded from a nib.


Since we implement this method, it means that this view will be loaded from a nib from somewhere else in our application. 


- (void)viewDidLoad {

    [super viewDidLoad];

    self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];      

}


We apparently want to change the background colour after loading, but to make everything work as intended we also call the 'viewDidLoad' method of our superclass to take advantage of the functionality it provides.


Examining of the xib-files


Finally, we have looked at the basic funcionality of all the classes in our project. Let's move on to the xib-files!


Resources/MainWindow.xib


File's owner


CMD-4 reveals that the object which is going to use ("own") this file is of the class "UIApplication", just like we've seen before. As we know by now, UIApplication objects has a delegate object which implements the UIApplicationDelegate protocol. Specifying the delegate object can be done fron IB by setting the 'delegate' outlet of an UIApplication object. CMD-2 reveals that this object's delegate outlet is set to "Util1 App Delegate".


Util1 App Delegate


CMD-4 shows that the class of this object is "Util1AppDelegate". It also shows that this class has two outlets; 'rootViewController' which is of type "RootViewController" (one of the classes we defined ourselves in the project) and 'window' of class UIWindow. CMD-2 shows that 'rootViewController' is connected to "Root View Controller" and 'window' is connected to "Window".


Root View Controller


CMD-4 gives us that this object is of the class "RootViewController" (one of our classes). and that it has an outlet called 'infoButton' of type UIButton. It also shows us something we haven't seen before - an "action" called 'toggleView' of type id. If you have forgotten where this come from, take a look at "Application Controllers/RootViewController.h" in XCode by pressing the small right-arrow icon in the title bar above the 'toggleView' row in the "Class actions" box in the Identity Inspector (CMD-4).


This is getting exciting, so let's have a look at the connections right away! Press CMD-2 and you'll see that 'infoButton' is connected to something called "Light Info Button" and 'toggleView' is connected to "Light Info Button Touch Up Inside". You might have noticed that this object apparently also has an outlet called 'view' which is connected to something called "View". These are here because "RootViewController" is a subclass of "UIViewController" and that's where the 'view' outlet comes from. In fact, UIViewController has two other outlets as well; 'navigationItem' and 'tabBarItem'. Take yet another look at the "Root View Controller" connections (CMD-2) and you'll find those two there as well, but not connected to anything.


By the way, if you want to verify that these outlets really come from UIViewController, bring up the Library (CMD-L) and drop a "View Controller" in the MainWindow.xib window. Select it and press CMD-4 and you'll see all the outlets mentioned above . When you're done verifying, select the "View Controller" icon and press backspace to get rid of it.


A short note on the section "Referencing outlets". Select "Util1 App Delegate" and press CMD-4. In the "Referencing outlet" section you'll see a "connection" that looks like this: 'delegate' -- 'File's owner". What this means is that the outlet 'delegate' in the object 'File's owner' points to this object. If you read it from right to left it becomes even clearer: "File's owner".delegate = "this object".


Ok, lets leave the generic UIViewController and return to our view controller. As mentioned above the 'view' outlet is connected to an object called "View", but how come we see no icon for it in the xib-file contents window ("MainWindow.xib"). That's because you can embed objects in other objects in IB and that is exactly what the author of this xib-file has done.


To reveal these embedded objects, we have to change the view mode of the contents window, which you do by pressing one of the small icons in the upper left part of the window - just above the text "View mode". Press the middle one and you'll be presented with a hierarchical navigation view mode (tree mode). Click the arrow to the left of "Root View Controller" and the mystical "View" object should appear. Press the arrow to the left of that one and the even more mystical object called "Light Info Button" should appear. If you are really really observant you could also find these - or at least the info button - by double clicking the "Root View Controller" icon in the "normal" view mode of the contents window. (Hint: it's in the lower right corner of the window that appears if you try it...)


By they way, if you wonder about how to embed an object into another object you do that by dragging the object you want to embed onto the other object. That's how View was put into "Root View Controller". For buttons and elements where the position is important, you can also position them at the same time as you embed them. Try that by double-clicking "View" in the tree view. This should bring up a "blank window". The info button already present is barely visible in the lower right corner. Bring up the Library (CMD-L) and drag a "Segmented Control" from the "Inputs & Values" section into the blank view. It should immediately appear and you can position it and size it at will. Check the tree view of the contents window to confirm that it appeared under View in the tree. Remove it by selecting it and pressing backspace, when you're done playing.


View


When you are in the "tree mode" it becomes easy to select the View icon so do that and press CMD-4 and then CMD-2. Nothing exciting, it's a simple UIView object with no outlets and no connections.


Light Info Button


In tree mode it's just as easy to select the "Light Info Button" icon and press CMD-4. Hey, not even this was that exciting - it's just a simple "UIButton"! Ok, maybe CMD-2 will make things a bit more fun? Wow, look at the list of... "stuff" that appears! If you look closer you'll see that the "stuff" actually are called "Events" and apparently we have done something with one of them - "Touch Up Inside". It looks like this event is "connected" to "Root View Controller toggleView". Sounds familiar? It should, because we mentioned it above. We earlier saw that we defined an IBAction called 'toggleView' in RootViewController.h, something which you can also see by selecting the "Root View Controller" icon here in IB and pressing CMD-2. Cool! It thus seems as if "events" are connected to "actions". Sounds reasonable!


Let's dig deeper into this. If you bring up XCode and do a project-search for 'toggleView' by pressing CMD-F you'll see that it is defined in RootViewController.h simply as -(IBAction)toggleView and then it is implemented as a method in RootViewController.h using the same "signature". Could it be that this method gets called when the info button is pressed. Yes, that's right! Or actually it gets called when the "Touch Up Inside" event is generated by the button, which means that you have to touch the button ("touch down") and remove your finger ("touch up") while the finger is still "inside" (hoovering over) the button.


One mystery remains for the infoButton. How did the iPhone know that we wanted a button which looked liked a the letter "i" inside a ring? Press CMD-1 to find out. Here you'll see that the type is specified as "Info Light" and that explains that mystery!


Window


Double click the Window icon and a black window appears. CMD-4 reveals that it is a plain UIWindow and CMD-1 confirms that the background colour is set to black.


Resources/MainView.xib


File's owner


CMD-4 shows us something new. The "File's owner" objects we have worked with so far have all been UIApplications, but this one is of the class "MainViewController", which is one of our own classes. We see that it has no outlets of its own, but if we switch to the connections tab (CMD-1) we see that the three outlets inherited from its superclass UIViewController are there; 'navigationItem', 'tabBarItem' and 'view'. The 'view' outlet of the superclass is connected to something called "Main View" and if you take a look at the xib-file contents window (MainView.xib), you'll see where "Main View" came from - yes there is an object in this xib called just that.


Main View


CMD-4 says this object is of class "MainView" and that it has no outlets of its own. CMD-2 shows that there are no inherited outlets as well. However, we see that there exists a connection via a "Referencing outlet". Using the syntax from above, this means that "File's owner".view = "this object". In our case "File's owner" is of the class "MainViewController", which in its turn is of the class "UIViewController", which in its turn has an outlet called 'view and that's the outlet that this object is connected to.


Resources/FlipsideView.xib


File's owner


CMD-4 shows that the class of the object is "FlipsideViewController" and that it has no outlets of its own. CMD-2 shows that the standard UIViewController outlets are there and that one of them, 'view', is connected to "Flipside View"


Flipside View


CMD-4 gives us a class of "FlipsideView" and no outlets. CMD-2 shows a "referencing outlet" meaning that "File's owner".view = "this object".



Summary


Wow, what a ride! We have learned a lot this time, but even after digging through so much one mystery remains and that is how the "title bar" and "Done"-button on the "flipside" was created since we saw no trace of them in Interface Builder, not even after learning about the "tree view" of the xib-file contents window. Well, that's beacuase those GUI elements were created programmatically, that is by writing Objective-C source code, but we won't analyse that here since we're now trying to focus on the IB. If you're curious about how that works I suggest you go back to XCode and do a project search (CMD-F and remember to enable "ignore case") for "navigation". Hmm, that sounded like an excercise for the reader to me ;) Good luck!


Tutorial: Creating an iPhone xib-file from scratch in Interface Builder (IB)

In the last post we analysed the contents of MainWindow.xib in order to try to understand how Interface Builder (IB) works and what you can use it for. This time we will try to create an IB-file from scratch in IB, since syntehsizing (creating) something often is the best way to confirm that you really understood everything you learned while analysing a subject.

Start IB, choose File/New from the meu and select the "Empty" template. This creates a xib called "Untitled" which contains "File's owner" and "First responder".

Select "File's owner" and press CMD-4 and you'll see that it is of the class NSObject. The owner of the xib-file we are currently creating is an object of type UIApplication, so we should start by changing the class to that. To do that, press CMD-4 and choose UIApplication from the drop-down list.

As soon as you do this an outlet called 'delegate' is automatically added in the "Class outlets" section. This is because an UIApplication normally is connected to an object which implements the UIApplicationDelegate protocol and that's where the 'delegate' name comes from.

The next natural step therefore is to create an object which implements that protocol. We have aldready defined such a class in XCode called "Test1AppDelegate" (see last post), so we'll create an object of that class.

Choose "Tools/Library" from the menu or press CMD-L. Select "Cocoa Touch Plugin/Controllers/Object" and drag the object icon into the "Untitled" window. This creates an object simply called "Object" in our IB-file.

CMD-4 reveals that this newly added object is of class NSObject, but we want it to be of class "Test1AppDelegate". Since this is a non-standard class that exists only in our project, we need to import the class definition/specification so that IB understands how to use it. To do this, choose "File/Read Class File" from the menu and navigate to Classes/Test1AppDelegate.h and select it.

Select "Object" again from the file contents window ("Untitled")  and press CMD-4. Now you should be able to select "Test1AppDelegate" as the class for this object. You should also see that this class has one outlet of type UIWindow with the name'window', which should be familiar since that is our window.

Let's connect the 'window' outlet to an UIWindow! To do this, we first have to create an UIWindow object, so press CMD-L to bring up the Library window. Choose "Windows, Views and Bars" and drag the Window-icon into the file contents window ("Untitled"), that is, drop it right beside the "Test1 App Delegate" object we just created.

To connect the 'window' outlet of "Test1 App Delegate" to the UIWindow object we just created, position the mouse over the "Test1 App Delegate" icon and press and hold the CTRL-key. Keep on holding the CTRL-key and press and hold the mouse button while moving the mouse pointer towards the Window icon. A blue line should appear, going from the the icon to the current position of the mouse pointer. Release the mouse button when the pointer is positioned over the Window icon.

Now a small pop-up window called "Outlets" should appear. Select the 'window' outlet, which should connect the Window object to the 'window' outlet of "Test1 App Delegate". To verify this, select "Test1 App Delegate" and press CMD-2. The 'window' outlet should have the value "Window", which is the IB-name of the UIWindow object we created a minute ago.

Now we should make "Test1 App Delegate" the delegate of our UIApplication, which is called "File's owner" here. Repeat the CTRL-drag procedure from above, but this time drag from "File's owner" to "Test1 App Delegate" and select the 'delegate' outlet. Done!

This procedure of CTRL-dragging between icons to connect an object to an outlet is in my view a bit counter-intuitive since I think the direction you have to drag the mouse is "wrong". To connect one of object A's outlet to object B, you should CTRL-drag from A to B. For me, it would have been more intuitive to instead CTRL-drag from B to A, if I wanted to connect B to A, but I guess that's just a matter of perspective.

To help us verify that we have actually succeeded in re-creating a "copy" of the MainWindow.xib file that was automatically created for us by XCode, click the Window icon and press CMD-1. Locate the box where you can set the window's background colour and set it to green or some other colour than the default white. As a final step, save the xib as "MyMainWindow" in the "Test1AppDelegate" project. IB will ask if you want to add it to your project which is exactly what we want so answer yes.

Go back to XCode and drag the MyWainWindow.xib file to the resources folder and then click on Resources/Info.plist to change MainWindow to MyMainWindow. This instructs iPhone to use our re-created xib-file instead of the one that XCode created for us.

Build and run the project by pressing CMD-Return and you should be presented with a green screen instead of a white one. Wow, we managed to quite easily create our own xib-file from scratch and "integrate" it in the application we created in XCode!


Sunday, April 5, 2009

Tutorial: Understanding the iPhone Interface Builder (IB)

In november 2008, I decided to start exploring the Apple iPhone development environment. The main reason for doing that was that I wanted to port a mobile game I wrote for the Mophun platform five years ago. Another reason was that I thought the iPhone seemed like an exciting platform.

Before starting to code I took the time to read quite a lot of official documentation from Apple. The primary problem with the Apple iPhone documentation in my view is that there is so much of it that it becomes hard to choose what to read. A secondary, but quite important, problem is that a lot of the documentation contains the wrong information, at least for someone who isn't familiar with Mac development. That the documents contain a lot of words, but little information is also quite frustrating. Thankfully, the API documentation available in XCode is much better.

However, I managed to find a handful of good documents and after reading them I thought I was well prepared for iPhone development. At this time there was almost no tutorials, blogs or discussion forums on the Internet since the Apple NDA had just been lifted. Therefore I started to explore on my own and got a complete chock when I started up the Interface Builder (IB). I didn't understand anything, which made me feel like a complete fool. Especially after spending so much time reading documents.

I quickly gave up the IB and started doing things programmatically instead, that is, doing everything by hand in source code; creating windows, views, buttons, etc. This turned out to be really simple so my self confidence was (partly) restored. It also made me feel that the problem wasn't my lack of understanding, but the lack of good documentation for the IB - see what a little self confidence can do ;)

A few days ago, I decided to return to IB and make a new attempt at understanding it. This time it went a little better since I had gained a lot of real iPhone experience since the last attempt. To force myself to really understand it, I decided to start by trying to fully explain the code and xib-files created by the XCode project templates.

Create the project.
  • Start XCode or choose "File/New project" from the menu-bar if XCode already is running.
  • In the left column, select: "iPhone OS/Application".
  • In the right box, select: "Window-Based application".
  • In the right bottom of the window, click the "Choose"-button.
  • Rename the project to "Test1" (that's the figure one, not the letter ell) by replacing the text "Untitled" in the "Save as"-box and save the project an appropriate place and press the "Save"-button.
After completing these steps, XCode will create a set of files for you which are displayed in the left column of the window using an expandable tree-view. Below is the hierarchy of files we will concentrate on in this post:

Test 1
  Classes
    Test1AppDelegate.h
    Test1AppDelegate.m
  Resources
    MainWindow.xib
    Info.plist

Explanation of the files

Classes/Test1AppDelegate.h

This is the h-file (specification) for the class in our application which will handle events/messages from the UIApplication-object which exist in all iPhone applications. Let's look at the most import lines of code.

Test1AppDelegate : NSObject <UIApplicationDelegate> {
Specifies that this object inherits from NSObject and implements the UIApplicationDelegate protocol. (A protocol is similar to an interface in Java.)

UIWindow *window;
The object will make use of an UIWindow which is the "base GUI component" in an iPhone and container for all other GUI components. Therefore we create a pointer to our window, which we will call 'window'.

@property (nonatomic, retain) IBOutlet UIWindow *window;
Properties are more or less instructions to the compiler to generate accessor methods (getters and setters) for a property (member field/variable) of the object. Here we want our variable 'window' to be accessible to other objects, so the compiler will create declarations for it here in the h-file. We also flag the property with 'IBOutlet' so that we can manipulate the it using IB.

Classes/Test1AppDelegate.m

This is the m-file (implementation) of the class Test1AppDelegate.

synthesize window
Instructs the compiler to create the actual accessor method (set/get) definitions (implementation), according to the instructions in the @property declaration in the h-file.

- (void)applicationDidFinishLaunching:(UIApplication *)application {
This method is part of the UIApplicationDelegate protocol and gets called when the application has finished launching(!).

[window makeKeyAndVisible]
This line calls the method makeKeyAndVisible in our window 'window'. What might seem strange here is that we so far hasn't seen any code for creating the window, just a declaration of the window in the h-file. This is because we don't create this window programmatically (in source code), but instead use IB to create, but more on that later.

Resources/MainWindow.xib

This is an IB-file, which was created automatically by XCode when we chose to create a "Window-Based Application" project. We will return to this file soon.

Resources/Info.plist

This is a "property list" which lists same basic properties for the application we are creating. Click it to see its contents. The most important property is the "Main nib file base name" which is set to "MainWindow", meaning that it points to the file Resources/MainWindow.xib in our project. The xib-file listed in the property will be automatically loaded by the iPhone when the application is started.

A first test run

In order to see some action, lets try to build and run our application to see what it does. In XCode, choose "Build/Build and Go" from the menu or simply press CMD-Return. This should bring up the iPhone simulator and display a completely white screen. Not too exciting, but quite impressive considering we still haven't written a single line of code ourselves. Press the Home-button on the iPhone simulator and navigate to the last page of icons on the home screen and you should see an icon called 'Test1' - yes, that's our little application!

Interface Builder (IB)

Ok, now it's time to start exploring the IB. First of all, the most important thing to understand about the IB is that it creates actual Obejctive-C objects and not source code! It can also set the properties of the objects, for example to "connect" two objects two eachother (by setting a pointer in object A to point to object B). The created objects, including the values of their properties, are then saved into a xib-file which can be loaded by the application. When the file is loaded the objects are re-created by the application in run-time. (For Java-coders, this is similar to reading a file containing serialised objects.)

To start IB, double-click Resources/MainWindow.xib. This will start IB and bring up some windows, where the window titled "MainWindow.xib" is the starting point. This window displays the content of a xib-file, in this case our xib-file called MainWindow.xib.

File's owner.

This object represents the object which eventually will load this xib-file - the object which "owns" this xib-file - and that is why it has the very confusing name "File's owner".

In our case, the real object owning this xib-file is the UIApplication automatically created by the iPhone when our application is started. The UIApplication object knows it should load this xib-file since we specified it in the Info.plist file.

The most important tool in IB is the "Inspector window" which can be invoked from the "Tools/Inspector" menu. It has four "tabs" called "Attributes", "Connections", "Size" and "Identity", which can be reached directly from anywhere in IB by clicking on an object icon and then pressing CMD-1 to CMD-4 respectively. In my view, "Identity" (CMD-4) is the best place to start since it tells us what kind of object we are dealing with.

So, click on "File's owner" and press CMD-4. Here we can see that this object is of the class UIApplication. We can also see that this is where the strange name "File's owner" comes from. The most interesting thing we see, though, is that it has a property (or outlet as it is called here) called 'delegate' which has the Objective-C type 'id'. As you probably know, 'id' is an "object pointer", which means that this property should be set to another object. In this case it should be set to an object which implements the UIApplicationDelegate protocol.

To see the value of the 'delegate' property, press CMD-2 to invoke the "Connections"-tab. Here we can see that 'delegate' is set to 'Test 1 App Delegate', which might sound familiar to you if you looked at the other objects in the IB window 'MainWindow.xib' which displays the contents of the xib-file. Thus, it seems as if there exists a connection between the objects "File's owner" and "Test1 App Delegate" which both exist in our xib-file. Please note that the names "File's owner" and "Test1 App Delegate" are IB-names, not the real names of the objects. To see the real names of the objects, or actually the class of the objects, select an object and press CMD-4.

First Responder.

I haven't fully understood the role of this yet, so I will try to explain it later...

Test1 App Delegate.

Ok, let's check the "Identity Inspector" for this one by pressing CMD-4. We see that this object is of the class Test1AppDelegate and that it has an outlet called 'window'. That's the class we defined in Classes/Test1AppDelegate.h and Classes/Test1AppDelegate.m! As you can see, our UIWindow-property 'window' also showed up, thanks to the IBOutlet in Classes/Test1AppDelegate.h

If we check the object's connections by pressing CMD-2, we see that our 'window' property is set to "Window". This means that a UIWindow with an IB-name of "Window" has been created in IB and connected to our 'window' property. If we check the contents of the xib-file displayed in the MainWindow.xib window we see that there actually is an object there called Window. We can also see which objects reference this object, that is, the "reverse connections". In this case we can see that the "File's owner" object has a connection to this object as we explained above.

Window.

Now, we have finally reached a GUI-object! Select the Window icon and press CMD-4 right away. We see that the class of this object is UIWindow. Press CMD-2 to check the connections: apparently there exists a "reverse connection" from an object with the IB-name "Test1 App Delegate". This means that "Test1 App Delegate" uses this Window.

For an object of UIWindow class, the Attributes (CMD-1) and Size (CMD-3) tabs also contain information. Pressing CMD-1 we can see that the background colour has been set to white, so finally we find the explanation for why we saw a completely white display when we test run our application previously! Pressing CMD-3 we can see that the size is set to 320x480 which completely fills the iPhone's display, which always should be the case for windows.

Finally, we have now explained the contents of the xib-file! Do remember that when the xib-file is loaded, the Objective-C objects it contains are created and the properties set in IB are set in the created objects as well. This is the explanation for how so little source code can accomplish so much.