Dive Into Interface Builder

Tweet

A few weeks ago, Andy White gave us a quick tour of Xcode and walked us through the development of a simple “Hello, World” app for the iPhone.

In this tutorial, we’ll build on those learnings and introduce you to the Interface Builder, a companion to Xcode designed to allow you to quickly and easily develop interfaces for your apps. In the process, we’ll be building a simple app for the iPad: a big ol’ calculator we’ll call GrandeCalc HD.

Creating the Project

Creating the project starts with launching XCode and using the File menu to create a new project.

For this application we want to create a View-based application. Make sure to select iPad, because the default device family is iPhone. Don’t worry, your project will create code that is compatible with both devices—this selection just means that you’ll be using an iPad layout as a default for Interface Builder.

The next section of the project wizard asks you to name the project. I called mine GrandeCalc HD and gave it the namespace of com.jherrington.calculatorhd. You can call yours whatever you like.

When the project is created, you’ll see something like this:

This shows you the two primary Objective-C classes that drive the application. An Objective-C class has two components, the first is the interface definition of the class (including things like member variables, properties, and public methods); this is in the .h header file. The other is the implementation of the class in the .m file.

The first of your two classes is the application delegate. This is the class that handles application-centric events like starting up, shutting down, and so on. We won’t be touching that class at all. The other is the view controller. This is the class that hooks up to the interface elements in the view and responds to the user tapping on them. We’ll be adding some Objective-C code there.

Now that we have our application’s code skeleton, it’s time to build an interface. Start by looking in the Resources portion of the project as shown below.

The display area of the view is defined in a .xib file. This is an interface builder file that has localized (in this case, just English) versions of the interface. That file includes all of the controls, their layout and sizing, their text, tags, connections to the corresponding Objective-C classes, and so on.

We start editing that file by double-clicking it.

Building the Interface

Double-clicking the .xib file will bring up the Interface Builder. Once there, you’ll see three windows. One is a large window containing the contents of the view; a second smaller window has the toolbox of user interface elements that you see below.

This is where we’ll be grabbing the text display and buttons for our calculator.

The third window shows the contents of the .xib file as seen here.

This window will become important when we link the buttons and the label to the Objective-C class that does all the work. In this case, the First Responder object actually represents the Objective-C class that will handle all the events.

The next step is to drag and drop some buttons and a UITextField onto the view, and then start editing them. You can lay out and style your buttons however you like; the only key point is to set the Tag value of each digit button to the numeric value of the button. This way, we’ll be able to use the same event handler for each button using the tag value in our code as the relevant numeric value. Here’s how to set the Tag value of the number 6 button, for example:

The layout I came up with looked like this:

Don’t worry if yours looks a little different. As long as all the relevant buttons and the label are in place, we’ll be able to wire it up and make it into a functional calculator.

There’s one last step to take care of before we move on to developing our app’s logic: we want to make sure our interface handles device orientation changes (from portrait to landscape, or vice versa) gracefully. You can simulate the appearance of your app’s interface by choosing Simulate Interface from the File menu. Once the simulator has launched, try rotating the simulated iPad left and right with Cmd-left or Cmd-right. Whoops! Our interface doesn’t handle landscape mode very well at the moment. Let’s see what we can do about that. Each element in your layout has a set of options that determine how it will respond to changes in the device’s orientation. Select one of your buttons, then choose the ruler icon at the top of the properties window. You want to adjust your settings to look like this:

The important section is Autosizing. This defines how the element changes shape and position during a re-layout of the interface. The lines along the edge of the box define if the position of the element is fixed or floating relative to each edge of the screen. The controls on the inside of the box determine whether the element changes height or width on a re-layout. For the buttons and the text display, specify that they’re floating and that they change both width and height. To do this, make sure both arrows inside the box are solid red, and that the lines outside the box are dashed. Once that’s done, test the interface again: it should look fine in both portrait and landscape modes.

With the UI layout done, it’s time to head back to Xcode to work on the Objective-C.

The Logic

Objective-C view classes have two critical elements; IBActions and IBOutlets. An IBAction is a method that responds to an event (for instance, a button touch). An IBOutlet is a property that the class uses to connect to a user interface element (such as the number label in the calculator). If you want to listen for events, you’ll want to add IBActions. If you want to change the state of the interface, or read its current state, you’ll need IBOutlets.

Because IBActions and IBOutlets are public, they go into the header file. The header file for the calculator view looks like this:

#import
@interface GrandeCalc_HDViewController : UIViewController {
	IBOutlet UITextField* numberDisplay;
	float heldValue;
	int lastOpDirection;
}
@property (nonatomic, retain) UITextField* numberDisplay;
-(IBAction)numberClicked:(id)sender;
-(IBAction)dotClicked:(id)sender;
-(IBAction)plusClicked:(id)sender;
-(IBAction)minusClicked:(id)sender;
-(IBAction)equalsClicked:(id)sender;
@end

The only outlet is the numberDisplay field, which is connected to the number display in the view. There are then five actions; these correspond respectively to a number being pressed, and the dot, plus, minus, and equals buttons being pressed. In each case, a sender object is passed along. This sender is the UI element that generated the event. For example, this could be the number button that was pressed.

Since all the number buttons go to the same event handler, we’ll use the Tag value of those buttons to distinguish their numeric values. In the case of the dot, plus, minus, and equals, we’ll just ignore the sender, since we’ll only hook that up to a single UI element.

If you’re new to Objective-C, you should note that the member variables (like numberDisplay, heldValue, and lastOpDirection) are defined in the @interface block. Properties and methods are defined after that. In this case, there’s one property, numberDisplay, and five public methods. The numberDisplay property will be used by the interface to set and get the object pointer to the number display element in the UI.

The implementation for the view, which is held in the .m file, is shown below:

#import "GrandeCalc_HDViewController.h"
@implementation GrandeCalc_HDViewController
@synthesize numberDisplay;
- (BOOL)shouldAutorotateToInterfaceOrientation:
  (UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
- (void)didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
}
- (void)dealloc {
    [super dealloc];
}
-(IBAction)numberClicked:(id)sender {
	UIButton *buttonPressed = (UIButton *)sender;
	int val = buttonPressed.tag;
	if ( [numberDisplay.text compare:@"0"] == 0 ) {
		numberDisplay.text = [NSString
         stringWithFormat:@"%d", val ];
	} else {
		numberDisplay.text = [NSString
         stringWithFormat:@"%@%d", numberDisplay.text, val ];
	}
}
-(IBAction)dotClicked:(id)sender {
	numberDisplay.text = [NSString stringWithFormat:@"%@.", numberDisplay.text ];
}
-(IBAction)plusClicked:(id)sender {
	float curValue = [numberDisplay.text floatValue];
	numberDisplay.text = [NSString stringWithString:@"0" ];
	heldValue = curValue;
	lastOpDirection = 1;
}
-(IBAction)minusClicked:(id)sender {
	float curValue = [numberDisplay.text floatValue];
	numberDisplay.text = [NSString stringWithString:@"0" ];
	heldValue = curValue;
	lastOpDirection = -1;
}
-(IBAction)equalsClicked:(id)sender {
	float newValue = heldValue +
       ( [numberDisplay.text floatValue] * lastOpDirection );
	numberDisplay.text = [NSString
        stringWithFormat:@"%g", newValue ];
	heldValue = 0.0f;
	lastOpDirection = 0;
}
@end

Again, if you’re new to Objective-C, all this will take some getting used to, but even though the syntax is a little odd, you should be able to see some object oriented patterns familiar to Java and C++.

Just browsing across the code, you can see that each method starts with a minus and then has a method declaration. The minus means that it’s an object method. A plus would indicate a class method. The syntax of the method is exactly the same as in the header file, except that in this case there’s also a body to the method.

Within each method, you’ll find Objective-C code to implement the method. In that code, you’ll find basic C operations that you’re probably familiar with; for example, the arithmetic operators, and the way that variables are defined. The really unique part is in the object oriented invocation syntax of Objective-C.

Let’s have a look:

[NSString stringWithString:@"0" ]

This means create a new string with the value ‘0’. The @ symbol specifies that we want an Objective-C string, as opposed to a C string. And in this case, we’re calling a class method on NSString.

Now look at this command:

[NSString stringWithFormat:@"%@%d", numberDisplay.text, val ];

This is roughly equivalent to a call to sprintf. The format string in this case takes the current text value of the numeric display and appends the value of the digit that was pressed. All those brackets are confusing at first, but once you become familiar with them, they’ll begin to make sense.

Now with the code in hand and the interface set up, it’s time to connect the two using Interface Builder. Before doing that, you’ll need to build your project by clicking Build and Run in Xcode; this will ensure that Interface Builder has all the inputs and outputs available to it, so you can hook them up with your interface components.

Connecting the Interface to the Code

Interface Builder looks for the IBOutlet and IBAction elements of the Objective-C view class, and provides us with an interface to wire controls to them. To link up the buttons, first select that button, then go to the connections panel of the Inspector window (represented by a blue circle with an arrow).

From here, you can see all the events associated with the button. You can click on any of the circles and drag it to the File’s Owner item in the contents window. For our buttons, we’ll use the “Touch Up Inside” event. When you drop your event on the File’s Owner, you’ll see a popup that shows all the available IBAction methods. Just choose the appropriate one: numberClicked for a number button, plusClicked for the plus sign, and so on. Connect up all the buttons in this same way.

The final step is to connect the numberDisplay variable to the number display UI element. Start by going to the contents window and select the File’s Owner. That should show something like the figure below in the Inspector window.

You can then drag the connector for the numberDisplay to the user interface element in the layout area to link up the two.

At this point you can save the interface and close Interface Builder. Then try and run your application from the Xcode IDE. It should work more or less the way you expect a calculator to work. Of course, our application logic is very simple; there are plenty of ways you could refine the app’s behavior.

If the calculator fails to work, the issue is likely in the connections that you defined between the user interface (the .xib file) and the Objective-C file. Follow the instructions from the last article to add breakpoints to the click methods on the Objective-C class, and see if the methods are getting called. If they aren’t, go back to the Interface Builder to make sure that you wired up the correct events to the IBAction methods in the Objective-C class.

Where to Go from Here

This is just the tip of the iceberg when it comes to learning about Objective-C and development for iOS devices. In this article, we’ve learned how to put together a project, build out a user interface, and connect it to the back-end Objective-C class and make it do something. If the application you have in mind uses the network, there’s a robust HTTP library for you to use. If your ideal application is more graphical in nature, there’s an amazing Quartz graphics and effects library just waiting for your enjoyment.

Feel free to use the code in this article as a starting point. If you come up with something great, be sure to let me know and I’ll buy it on the App Store (assuming you keep it relatively cheap!).

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments