TweetFollow Us on Twitter

Built for iPhone 2.0

Volume Number: 24
Issue Number: 12
Column Tag: iPhone

Built for iPhone 2.0

Developing utility applications with the iPhone SDK

by Rich Warren

Getting Started

So, you're interested in dipping your big toe into the fast-pace world of iPhone development? Well, what are you waiting for? Grab a copy of the SDK from http://developer.apple.com/iphone/. Install it, and you're good to go.

iPhone applications are, in many ways, much simpler than desktop applications. There are fewer options, fewer moving parts to juggle. It's a great way to learn the basics of Objective-C and Cocoa programming.

Even better: you don't even need to own an iPhone or use your personal one as a text platform. You can use the built-in simulator to give the SDK a test drive. Of course, if you want to actually distribute your applications, you need to apply to the iPhone Developer Program, and you will want to test your application on real hardware. Let's not worry about the details. For now, lets ease ourselves into the world of iPhone development one small step at a time.

Three Flavors of iApps

The first step is often the hardest. Before we can begin building our application, we must have some kind of design, at least a rough sketch on a beer-soaked bar napkin. We're not looking for a laundry list of features here. iPhone applications should focus on a single task or a tightly integrated set of tasks. People use them while waiting in line at the bank, or during their walk from the parking lot to the restaurant. They want to get in, get their information and get out.

Generally, this means our application should focus on the users. What sort of data are they interested in? How will they interact with it? How can we make their experience as streamlined and hassle-free as possible? To help answer these questions, Apple has identified three different basic styles for iPhone applications: Utility, Productivity and Immersive.

Utility Applications

Utility applications typically present information with little or no interaction. Many utility applications focus on a single, main view. They use a clean, simple interface to display their information as clearly as possible. More complex examples may include multiple views through either a tab bar or a page control.

Like Dashboard widgets, Utility applications have an info button on the bottom right corner. When you press this button, the application flips over, revealing a configuration panel. This lets users make quick, frequent changes to the application's behavior.

Weather and Stocks are perfect examples of Utility Applications.

Productivity Applications

Productivity applications manage complex, hierarchical data. Typically these applications are organized as a series of tables. Make a selection on one table, and a new list of options slide into place. The application starts with the most general information, with options growing more specific as you slide to the right. Productivity applications also make heavy use of navigation and tab bars. However, they use little or no custom drawing.

Productivity applications often have more-complex preferences, but the preferences do not change very frequently. Instead of showing the preferences within the application itself, the productivity application integrates its preferences into the iPhone's Settings application.

Mail is undoubtedly the stereotypical productivity application. The Settings app and, to a certain extent, the iPod app also fall into this category. Note: productivity applications are not necessarily limited to traditional productivity-oriented tasks, like ToDo lists and calendars. Any application that focuses on data and organization may benefit from the productivity style.

Immersive Applications

Immersive applications use the entire screen to provide an engaging view into the application's content. These applications always have a strong visual focus. They usually hide the status bar to maximize screen space. They use few if any common controls, favoring custom-drawn interfaces, and they are often designed to view horizontally.

Immersive applications include games, multi-media and graphics applications. The iPhone's video interface is a perfect example of an immersive application.

Above and Beyond

These three styles provide a solid foundation for building your iPhone application, but don't feel trapped or limited by them. They simply represent tested solutions to the most-common use cases. You will find many advantages to following these styles. Apple's developer tools provide excellent support for building these applications. Additionally, since many of Apple's own applications follow these styles, users already understand and feel comfortable with these designs.

Still, some of the original iPhone applications fail to remain squarely in any one category. When you first open the iPod app, it appears to follow the productivity style, focusing on the hierarchical organization of your media. However, the Cover Flow, Now Playing and Video views shift dramatically to the immersive.

Part of the fun of designing applications for the iPhone is simply experimenting with the interfaces and form factor. Don't forget to have fun! Use these styles as appropriate, but feel free to strike out on your own from time to time.

Tools of the Trade

Apple has done an excellent job designing the iPhone SDK so that developers can leverage their existing Cocoa knowledge. The tools and the APIs will feel very familiar, however, looks can be deceiving. In some important ways, iPhone applications are very different from their desktop cousins.

Let's take a quick look at the tools used for iPhone development, while paying special attention to any surprises that may be lurking in dark corners.

Xcode

If you've done any Cocoa development, you're already familiar with Xcode. If not, Xcode is Apple's IDE; your one-stop shop for all your code mangling and debugging needs. Don't worry, we'll step through the basics soon enough.


Xcode's iPhone Projects

Xcode 3.1 offers complete support for the iPhone SDK. This includes six different iPhone templates. The Utility Application template sets up a typical utility application. This includes the application's main view, the flipside view and the buttons to navigate between them. We'll take a detailed look at this template later on.

The Navigation-Based Application and the Tab Bar Application provide solid starting points for productivity projects. The Navigation-Based Application starts with a navigation bar and a table view. The Tab Bar Application gives you a tab bar and two views that you can toggle between.

Next, the OpenGL ES Application provides a view and animation timer. The template also includes a sample animation to get you started. Not surprisingly, the OpenGL ES Application template is an ideal starting point for any OpenGL-based immersive applications.

The last two templates, View-Based Application and Window-Based Application, provide simpler starting points for those who like to roll their own. The View-Based template provides a view controller and a single nib-based view. The Window-Based Application starts with even less.

We can use the View-Based and Window-Based templates to build any style of application. In particular, we can use them as starting points for immersive applications based on Quartz or Core Animation instead of OpenGL ES. Also, these applications provide ideal starting points for unusual applications that defy our regular classifications. We could even use them to build typical utility or productivity applications, but I would not recommend it. The other templates give you so much functionality for free. In general, you should always try to use the built in features first; save the custom code for when it's absolutely necessary.

Xcode also provides access to a vast library of information. Select Help --> Documentation to bring up the documentation window. To save time on the downloads, Xcode initially ships with only stubs to the core documents. To get the full libraries, you must subscribe to the appropriate documentation set.

In the documentation window, simply click the Get button next to the doc set you wish to install. I'd recommend subscribing to at least the Core Library, Developer Tools Library and iPhone OS Library. Be patient, these downloads can take a while. However, once they're installed, Xcode will automatically check for any updates every time you open the documentation window.


Xcode's Documentation

For more information on Xcode, check out Apple's Xcode Overview in Xcode's documentation.

Interface Builder

Interface builder lets us visually design our user interface. But it's more than that. We can also draw connections between the interface and our code, linking controls with actions or elements. The Interface Builder saves the layout and objects in either a *.nib or *.xib file. For the most part, the difference is unimportant. xib is a newer, develop-time format. It stores the nib as a flattened text file. This provides better integration between Interface Builder and Xcode, and makes xib files diff-able, more refactorable and SCM friendly. Finally, xibs are compiled into nib files when you build the application.

iPhone applications always use xib files. However, for historical reasons, both files types are commonly referred to as nibs. [Ed. note -- The term "nib" comes from NeXT. Remember them? NIB is an abbreviation for NeXT Interface Builder.]

Your application loads its nibs, creating instances of all the objects contained within.

Interface Builder becomes somewhat simpler when designing views for the iPhone. We don't have to worry about menus or bindings. Our window always fills the entire screen. The user cannot resize it or open multiple windows. This means we only need one window per application, and we can just swap in alternate views as necessary.

We should always keep our nib files as small as possible, but this is particularly true for the iPhone. Apple strongly recommends placing each view in its own nib. This allows us to load and unload the views individually. By default, view controllers respond to didReceiveMemoryWarning messages by purging any views that are not currently in use. Using one nib per view helps facilitate clean memory management.

Interface Builder has three main windows: the Document Window, the Library and the Inspector, plus any views or windows we are designing. The Document Window contains our top-level objects. Typically, this includes the File's Owner, First Responder, any additional controllers and any top-level views or windows. The Library contains a selection of controllers, views and controls that we can drag onto our user interface. Meanwhile, the Inspector allows us to view and edit the settings of any currently selected item.


Document Window


Library


Inspector

In general, Interface Builder development consists of dragging items from the library. Controllers and top-level windows or views are typically placed in the Document Window. Controls and subviews are placed directly on the desired window or view. We then resize our controls and views, and adjust their settings in the Inspector. Finally, we draw connections between the controllers in the document window and the controls on our user interface.

When building iPhone applications, any top-level window will have an arrow button in the upper right corner. This allows you to easily rotate between the horizontal and vertical orientations. However, if you're working on a View, you don't get a rotate button. That's a shame. Often your actual controls are located on the View, not the Window, and there is no easy way to check and see how your view will look when the iPhone is rotated.

Don't worry if this seems confusing. We'll get some hands on practice real soon, but if you would like more information on Interface Builder and nib files, check out Apple's Interface Builder User Guide in Xcode's documentation.

Instruments

Instruments allows us to examine the inner workings of running code. When working on iPhone projects, instruments allows us to collect data from either the simulator or the iPhone itself.

Instruments appears similar to GarageBand. You drag instruments from the library - each one monitors a specific type of data. You can modify each instrument's settings. Then select the desired executable and press the Record button. Instruments will gather data as your application runs, allowing you to explore it and look for problems.

You can also save the data, to explore it in more detail later, or to compare performance across different trials.


Instruments

Given the iPhone's limited resources, tuning an application with Instruments is a vital step in application development. At a minimum, you should look for and fix any memory leaks. You may also want to monitor CPU usage and look for performance bottlenecks. You should start exploring your application early in the development process. Leaving it to the end only makes problems harder to find and fix.

Finally, while you can use Instruments with the simulator for some early testing, the simulator does not accurately represent your application's performance on the iPhone itself. You should always do your final testing on the actual iPhone hardware.

For more information on Instruments, check out Apple's Instruments User Guide in the Xcode documentation.

Objective-C and Cocoa Touch

These may not be actual tools - they're more like the raw materials that we use to shape our applications. Semantics aside, there are several important issues we should consider before moving forward.

The iPhone SDK uses a subset of Objective-C 2.0. This includes many powerful technologies: properties, fast enumeration, and key-value observing. However, it does not support garbage collection. Not yet, at least.

That means, before you can develop iPhone applications, you must understand memory management in Objective-C. It's not hard, especially when we use properties, but it does require a bit of care and attention. Basically, you must release anything you create or anything you retain. We'll look at some examples in the tutorial below, but to really understand the topic, check out Apple's Memory Management Programmer's Guide for Cocoa in Xcode's documentation.

If you're an experienced Cocoa programmer, you'll quickly notice that many of the AppKit NS* classes have been replaced by new UI* classes from Cocoa Touch's UIKit. Many of these classes have similar names and play similar roles, but there are some subtle (and sometimes not-so-subtle) differences. When in doubt, check the documentation.

Also, even though Cocoa Touch includes most of Cocoa's features, it doesn't duplicate everything. The biggest exceptions, in my opinion, are the lack of Bindings and Core Data. Maybe I'm just lazy, but I've grown used to letting Bindings and Core Data do much of the glue work for me. Having to go back and make all these connections by hand feels like I've fallen into the Stone Age. Maybe Bindings and Core Data are just not efficient enough for an embedded device? Maybe they're features Apple will add in the future? Regardless, they're not here now, and that's a shame.

The iPhone can also be rather draconic when it comes to shutting down the application or managing memory. As you've probably heard, the iPhone does not support running third-party applications in the background. More importantly, our active application will shut down whenever the user presses the home button, or whenever the phone receives an incoming call. This means, our application could shut down at any point in time - whether or not the user wants it to.

Just before the application shuts down, the iPhone OS sends our application delegate an applicationWillTerminate: message. This allows us to perform any necessary cleanup and save off our state before closing. However, our application must respond quickly. If it does not exit on its own within 5 seconds, the OS will kill the process outright.

Also, due to the iPhone's limited resources, there are a number of memory warnings that we must listen for. The iPhone OS's virtual memory does not include any swap space. When memory begins to run low, the OS will send a message to the running application. The application delegate receives an applicationDidRecieveMemoryWarning: message. We can override this method to free up memory.

Additionally, each UIViewController subclass will also receive a didRecieveMemoryWarning message. By default, our application will release any views that are not currently being used. It will then recreate the views later, if they are needed again. However, we can override didRecieveMemoryWarning to change this behavior, or to perform additional memory management at the controller level.

Finally, our application can register to receive UIApplicationdidRecieveMemoryWarningNotification messages. This can be particularly useful when we have more than one object that manages our purgeable resources - particularly if we do not need to coordinate between these objects. If we want a more coordinated purge, we probably need to organize it at the application level, through the application delegate's didRecieveMemoryWarning method.

It is vitally important to clean up as much memory as quickly as possible. If the memory shortage persists, the iPhone OS will shut down the entire application.

For more information on development for the iPhone, check out the iPhone OS Programming Guide, in Xcode's documentation.

Color World Tutorial

For the rest of this article, we will explore the iPhone SDK by building a simple utility application. Color World displays and hides the message "Hello, World!" when the user presses its button. If you go to the FlipsideView, you can set the color for both the text and the main View's background.


Main View


Flipside View

Build the Project

Open Xcode and select File --> New Project.... In the New Project window, make sure iPhone OS application is selected in the left-hand table. Now double click the Utility Application icon. A Save sheet should drop down. Type "Colorful World" for the project's name, and set an appropriate location.

Xcode now opens your new project. Let's take a second to get ourselves oriented. In the Groups & Files tree, you should see several folders under the Colorful World project. We will primarily use files from the Main View, Flipside View, Application Controllers and Resources folders. Main View contains the header and implementation files for our MainView and MainViewController. Flipside View holds similar files for our flipside view. Application Controllers manages the Colorful_WorldAppDelegate and our RootViewController. While the Resources folder holds all our nibs: FlipsideView.xib, MainView.xib and MainWindow.xib.


Groups & Files

Go ahead and press the Build and Go button from Xcode's toolbar. This will automatically launch our application in the simulator. As you can see, it doesn't do much yet. The main view is just a gray background, with the info button in the bottom right corner. However, if you click on the info button, it automatically flips to the FlipsideView, which is dark grey with a black navigation bar and a nice blue Done button. As you can see, we get quite a bit of functionality for free.

Build our Model

iPhone applications typically follow a Model-View-Controller (MVC) design pattern. The MVC paradigm divides a complex application into logical chunks. The Model manages the application's data. The view displays the data. And the controller handles user interactions. Xcode has already built stubs for our views and controllers. All we need now is a model.

Create a new group by right clicking on Colorful World in the Groups & Files tree. Select Add --> New Group. Then rename the group Model. Now right click on our Model group and select Add --> New File.... In the New File window, make sure iPhone OS Cocoa Touch Classes is selected. Double click NSObject subclass. In the New File window, type Model.m for the file name. Make sure also create "Model.h" is checked. Then click Finish.

Our model is incredibly simple. Open the interface file, Model.h. Make the changes shown below:

Model.h

This is the interface for Colorful World's Model.

@interface Model : NSObject {
   
   UIColor *viewColor;
   UIColor *labelColor;
}
@property(readwrite, retain) UIColor *viewColor;
@property(readwrite, retain) UIColor *labelColor;
@end

This simply creates two UIColor member variables, and declares properties to provide read/write accessors for these variables. Technically, all properties are read/write by default, so the property lines could be simplified to @property(retain) .... However, when building more-complex objects I often find it helpful to explicitly define my properties.

viewColor defines the background color for our main view. labelColor defines the message text color (when visible).

Now, open the implementation file (Model.m). Again, make the changes listed below.

Model.m

The implementation for Colorful World's Model.

@implementation Model
@synthesize viewColor, labelColor;
- (id)init {
   
   if (self = [super init]) {
      
      self.viewColor = [UIColor lightGrayColor];
      self.labelColor = [UIColor whiteColor];
   }
   return self;
   
}
- (void)dealloc {
   
   [viewColor release];
   [labelColor release];
   [super dealloc];
}
@end

This is almost as simple as the interface. @synthesize creates the accessors for our properties. init sets our default colors. Note: since we use our properties to store the colors, we do not need to worry about retaining them. Our accessors handle that automatically. However, we do need to release our colors when the model is disposed. Not surprising, that is done in the dealloc method.

That's it. Our model is done.

Add the Model

Both the main view and the flipside view need to access our model. There are several ways we could manage this. Probably the simplest is to just add our model to our application delegate. Our view controllers can then access our model through the delegate.

First, open Colorful_WorldAppDelegate.h and make the changes shown below:

Colorful_WorldAppDelegate.h

We add a model property to our application delegate.

#import <UIKit/UIKit.h>
@class RootViewController;
@class Model;
@interface Colorful_WorldAppDelegate : NSObject <UIApplicationDelegate> {
   IBOutlet UIWindow *window;
   IBOutlet RootViewController *rootViewController;
   Model *model;
}
@property (nonatomic, retain) UIWindow *window;
@property (nonatomic, retain) RootViewController *rootViewController;
@property (nonatomic, readonly) Model * model;
@end

We're basically adding a model property to our delegate. To add the model, we must first make a class declaration for the Model object. Then we add a model instance variable. Finally, we declare that model is a property. Specifically, we say that the model is an unsynchronized, read-only property.

Now we need to synthesize and initialize our model. Open Colorful_WorldAppDelegate.m, and add the following code just below the other @synthesize lines.

[Colorful_WorldAppDelegate init]

Synthesize our model, and then initialize it in the delegate's default constructor.

@synthesize model;
-(id)init {
   if (self = [super init]) {
      model = [[Model alloc] init];
   }
   
   return self;
}

The init method creates a new instance of Model and assigns it to our model property. If you've been paying attention, you would have noticed a similar design used in Model's constructor. It may look a bit intimidating, but it's a common idiom for Objective-C. In theory, the call to [super init] could return an entirely different object, or nil, and our constructor may need to respond accordingly.

Finally, we need to import the header for our Model class. Add the following line just below the other imports.

#import "Model.h"

Build Main View

The RootViewController manages our main window, and handles transitions between the main view and the flipside view. The real work is done by the main view and the flipside view themselves. Actually, that's not true. Typically you won't ever touch the views, except in Interface Builder. Code-wise, the view controllers do all the work. They are responsible for loading and unloading new views, swapping views, managing auto-rotation, and responding to user-generated events. Let's take a look.

Open MainViewController.h, and change it to match the code below:

MainViewController.h

This view displays our message and a single button that turns the message on and off.

#import <UIKit/UIKit.h>
@interface MainViewController : UIViewController {
   IBOutlet UIButton *button;
   IBOutlet UILabel *label;
}
- (IBAction) buttonPressed;
@end

So, what have we done here? The two IBOutlet lines define pointers to objects in our main view's nib: one for the button and one for the label. Finally, we declare an action, buttonPressed, which (not surprisingly) is called whenever our button is pushed.

Just a quick note on IBOutlet and IBAction, IBOutlet has no real meaning outside Interface Builder. As far as our code is concerned, button and label are simply instance variables. The IBOutlet macro just alerts Interface Builder to the outlet's existence. This will allow us to draw connections using Interface Builder later on.

Similarly, but even more simply, IBAction equals void. Actions are just methods that don't take any arguments and don't return any values. Again, like IBOutlet, IBAction is a flag for Interface Builder, allowing us to draw the necessary connections later on.

OK, now open the implementation file (MainViewController.m).

First, lets look at an unmodified view controller. Ours has four methods and a commented-out stub. initWithNibName:bundle: is called to initialize MainViewController instances. Unfortunately, the nib has not been loaded at this point, so any outlets will not be valid. While you can do some initialization here, you cannot touch any objects that are loaded through the nib. Typically I wait and do all my initialization in viewDidLoad. Once here, all the nib-loaded objects are guaranteed to be valid.

Next, we have shouldAutorotateTo-InterfaceOrientation. iPhone OS calls this method whenever the iPhone's orientation changes. If you want to allow autorotation, you can simply return YES.

The OS also calls didRecieveMemoryWarning whenever the phone is running low on memory. By default, the OS will release any view controllers that are not currently in use. You can perform additional memory management here as well. Our application does not have any purgeable memory, so we will just leave the default implementation alone.

Finally, the runtime calls dealloc on an instance just before that instance is destroyed. Typically we release any references that we are holding, before calling the superclass's dealloc method.

Let's start by adding our initialization. Uncomment viewDidLoad and add the following code:

[MainViewController viewDidLoad]

Additional initialization for MainViewController.

- (void)viewDidLoad {
   id delegate = [[UIApplication sharedApplication] delegate];
   Model *model = (Model *)[delegate model];
   
   [model addObserver:self forKeyPath:@"viewColor" 
      options: NSKeyValueObservingOptionNew context:nil];
   
   [model addObserver:self forKeyPath:@"labelColor" 
      options: NSKeyValueObservingOptionNew context:nil];
   
   self.view.backgroundColor = model.viewColor;
   label.textColor = model.labelColor; 
 }

First, we get a copy of our model from the singleton UIApplication instance. Then, we use key-value observing to monitor our model. We register our MainViewController instance as an observer of both the viewColor and the labelColor properties. Anytime either of these properties change, we will receive a notification message.

Key-value observing is built into all NSObject subclasses. You can observe any value from any object, as long as that value is key-value compliant. Usually, this simply requires key-value compliant accessors for the member variable. By definition, properties autogenerate key-value compliant accessors, which is just another reason to use properties.

For more information about key-value observing, check out the Key-Value Observing Programming Guide in Xcode's documentation.

Once we're done registering with the model, we simply set our default colors. Notice that neither of these settings could have been made during the initWithNibName:bundle: method. The view and label values are both initialized when the nib loads.

Now, we need to catch the notifications from our model. Add the following method.

[MainViewController observeValueForKeyPath:ofObject:change:context:]

Catches any key-value observing messages to this object.

- (void)observeValueForKeyPath:(NSString *)keyPath
      ofObject:(id)object 
      change:(NSDictionary *)change
      context:(void *)context
{
   
   id newValue = [change objectForKey:NSKeyValueChangeNewKey];
   
   if ([keyPath isEqual:@"viewColor"]) {
      self.view.backgroundColor = newValue;
   }
   
   if ([keyPath isEqual:@"labelColor"]) {
      label.textColor = newValue;
   }   
}

This method will catch any notifications from any objects we are observing. We simply get the value of the change, then check to see which variable has changed. If the viewColor changed, we set the new background color. If the labelColor changed, we set the new text color.

Next, we need to build our button action. Just add the following method:

[MainViewController buttonPressed]

This method is called whenever the user presses the Display Message button.

- (IBAction)buttonPressed {
   
   Boolean hidden = label.hidden;
   
   if (hidden) {
      [button setTitle:@"Hide Message" forState:UIControlStateNormal];
   }
   else {
      [button setTitle:@"Display Message"   forState:UIControlStateNormal];
   }
   
   label.hidden = !hidden;
}

Here, we check to see if our label is visible. If it is visible, we set the button's text to "Display Message" and hide the label. If it's hidden, we set the button's text to "Hide Message" and make the label visible. Pretty simple, really.

Import the Model's header, and you're good to go.

Build Flipside View

Simple UI controls use IBOutlets and IBActions to communicate with their controller. More complex controls use delegates. Our flipside view will use a UIPickerView to select the background and text colors. This view will need a UIPickerViewDelegate subclass to communicate with.

Right click on the Flipside View group, and select Add

--> New File.... Add a new NSObject subclass and name it ColorPickerViewDelegate. Open the header file, and make the following changes:

ColorPickerViewDelegate.h

Interface for our UIPickerView delegate.

#import <UIKit/UIKit.h>
@class Model;
@interface ColorPickerViewDelegate : NSObject 
   <UIPickerViewDelegate, UIPickerViewDataSource> {
   
   NSArray *titles;
   NSArray *colors;
   Model * model;
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView;
- (NSInteger)pickerView:(UIPickerView *)pickerView 
   numberOfRowsInComponent:(NSInteger)component;
- (NSString *)pickerView:(UIPickerView *)pickerView 
   titleForRow:(NSInteger)row forComponent:(NSInteger)component;
@end

Our delegate contains an array of colors, an array of color titles and a pointer to our model. We implement two required methods from the UIPickerViewDataSource protocol (numberOfComponentsInPickerview: and pickerView:numberOfRowsInComponent:). We also implement two optional methods from the UIPickerViewDelegate protocol (pickerView:titleForRow:forComponent: and pickerView:didSelectRow:inComponent:). These methods allow us to create the row labels, and respond to any user selections.

Now open the implementation file. Again, make the following changes:

ColorPickerViewDelegate.m

The implementation of our UIPickerViewDelegate.
#import "ColorPickerViewDelegate.h"
#import "Model.h"
@implementation ColorPickerViewDelegate
-(id)init{
   if (self = [super init]) { 
      
      titles = [NSArray arrayWithObjects:  @"Red", @"Blue", @"Green", 
         @"Gray", @"Light Gray", @"White", nil];
      
      [titles retain];
      
      colors = [NSArray arrayWithObjects: [UIColor redColor], 
         [UIColor blueColor], [UIColor greenColor],[UIColor grayColor],
         [UIColor lightGrayColor], [UIColor whiteColor],  nil];
      
      [colors retain];
      
      id delegate = [[UIApplication sharedApplication] delegate];
      model = (Model *)[delegate model];
      [model retain];
   }
   
   return self;
}
}
- (NSInteger)numberOfComponentsInPickerView:(UIPickerView *)pickerView {
   return 2;
}
- (NSInteger)pickerView:(UIPickerView *)pickerView numberOfRowsInComponent:(NSInteger)component {
   return [colors count];
}
- (NSString *)pickerView:(UIPickerView *)pickerView titleForRow:(NSInteger)row forComponent:(NSInteger)component {
   return [titles objectAtIndex: row];
}
- (void)pickerView:(UIPickerView *)pickerView didSelectRow:(NSInteger)row inComponent:(NSInteger)component {
   
   UIColor * newColor = [colors objectAtIndex:row];
   
   if (component == 0) {
      model.viewColor = newColor;
   }
   
   else {
      model.labelColor = newColor;
   }
}
- (void)dealloc {
   [titles release];
   [colors release];
   [model release];
   [super dealloc];
}
@end

There's a lot going on here, so let's take it slowly. First, we declare an array of titles and an array of colors. The titles contain the names of each color, and are used to create our labels. The colors, on the other hand, will be sent to the model whenever the user makes a new selection.

The numberOfComponentsInPickerView: method simply returns the number of components we want for our view. For example, a four-digit combination lock view would have four components. Ours only has two: one for the background color, another for the text color.

The pickerView:numberOfRowsInComponent: method sets the number of rows in each component. A more complex view, like a date view, may have a different number of rows for each component. We use the same set of colors for both. Therefore, we just return the number of colors in our array.

The picker view then iterates over the rows in each component, calling pickerView:titleForRow:forComponent: on each one. This method returns the NSString title used to label that row.

Finally the picker calls pickerView:didSelectRow-:inComponent: whenever the user makes a selection. Here, we check to see which component the user altered, then update our model as appropriate.

Now, we need to attach our delegate to our picker view. We have two basic options, we can pull the picker view from the nib, or we can push our delegate into the nib. Either method works fine. I chose the first option, since it is slightly simpler.

Open FlipsideViewController.h. We need to add an IBOutlet for our picker view, and we need an instance variable for our delegate.

FlipsideViewController.h

The interface for our flipside view controller.

#import <UIKit/UIKit.h>
@class ColorPickerViewDelegate;
@interface FlipsideViewController : UIViewController {
   IBOutlet UIPickerView *colorPickerView;
   ColorPickerViewDelegate *delegate;
}
@end

Next, open the implementation file and implement viewDidLoad, as shown below:

[FlipsideViewController viewDidLoad]

Instantiates our delegate, then assigns it to the picker view.

- (void)viewDidLoad {
   self.view.backgroundColor = [UIColor viewFlipsideBackgroundColor];   
   
   delegate = [[ColorPickerViewDelegate alloc] init];
   colorPickerView.delegate = delegate;
}

Don't forget to import the ColorPickerViewDelegate header file, and don't forget to release our delegate in the dealloc method. But, other than that, we're done here.

Create the User Interface

We just need to build our views, and our application is done. Let's start with the main view. Within the Resources group, double click on MainView.xib. This will launch Interface Builder.

Drag a label from the library and center it on the view. Double click the label and type "Hello, World!" Its text value should change. Now, with the label selected, take a look at the inspector.

The first tab lets us set our attributes. We only need to make one change here. Our message should start out hidden. In the View, Drawing attributes, make sure Hidden is checked.

The second tab shows us our connections. We don't have any yet. Just move on.

The third tab allows us to change the size, fix the alignment and set the autoresizing. Of these, autoresizing is the most interesting. It lets us define how a UI element will behave when the window's size changes.

That may seem a bit odd for an iPhone application. After all, the user cannot resize the window, it always fills the screen. However, if you want your application to autorotate (or at least, if you want it to look halfway decent after you autorotate), you need to define appropriate autoresize settings.

Our application does not autorotate, so we can ignore those settings for now. Just make sure your label is centered horizontally. You probably want it somewhat above the vertical center.

The fourth tab shows us the selected object's class and any actions our outlets for that class. Again, we have none.

Drag a rounded rectangle button from the library and place it along the bottom of the view. As you move it around, you should see blue lines whenever you approach an edge, or when you are centered under the label. Use these to position the button, then double click the button. Type "Display Message". Again, we don't need to change any of the button's settings.

Now lets connect these items to our File's Owner. Right click on the File's Owner in the Documents window. This brings up a semi-transparent, dark-gray list of all the actions and outlets for the File's Owner. Move this list so that you can see both it and the view.

Find the button outlet. It should have an empty circle at the right edge of the row. When you hover your mouse over the circle, it becomes a plus sign. Click and drag from that circle to the button control on your view. Our File's Owner list should now show our connection. Now, click and drag from the label outlet to the label control.

Connecting the action is almost as easy. Drag from the button pressed action to the button control. This time, you will see a popup menu of options. Select Touch Up Inside. That's it. We're done with the main view. Save it and close it.


MainView.xib Connections


Main View

Now open FlipsideView.xib. Drag out a picker view. Center this at the top of the flipside view. Drag out two labels. Put one beneath the picker on the left side, and change the text to "Background". Put the other on the right and change the text to "Text". You may want to change the text color for these to something lighter, just to make them a little easier to see. You should also right align the "Text" label.

Again, right click on the File's Owner. Drag from the colorPickView outlet to the picker view control. That's it. You're done. Save and exit.


Flipside Connections


Flipside View

Take it for a Spin

Now's the moment of truth. Press the build and go button, cross your fingers and wait. If everything went well, the simulator should launch, and you should have a fully functional (if somewhat silly) application.

What do you do if things don't go as planned? Take a quick look through the errors and see if you can figure out what went wrong. Often, it's only worth looking at the first few error messages. A single mistake could spawn a cascade of rather strange errors. Try to fix the first thing on the list, then rebuild the application.

You can also look for common mistakes. Make sure there's a semicolon at the end of the line. Parenthesis and brackets always come in pairs. When you have nested functions, it's often easy to get off by one. Also, make sure you've imported header files wherever we've used custom objects. Finally, double-check the connections in Interface Builder.

A little patience and persistence, and the application will be up and running in no time. However, you're still not done. You should really launch the application in Instruments and check for memory leaks or performance bottlenecks. This application's so small, you shouldn't find much, but it's still an interesting exercise. For example, you will see sudden jump in memory usage once the flipside view is loaded.

Room for Improvement

Our program, as written, has two obvious bugs. First, when we switch to the flipside view, our picker should have the current colors selected. Second, we should not let the user select the same color for both the background and the text. I'll leave those as a homework assignment for you.

And for extra credit, try this. Our application should really save our model when the user presses the Done button on the flipside view. We should also load the model when the application starts. This way, our application will remember the users most recent color selection.

This is harder than the simple bug fixes above (hence the extra credit). But, you should be able to get through it. Take a look at the RootViewController's toggleView method, and read the section titled The Application Sandbox from the iPhone OS Programming Guide.

Good luck, and happy coding!


Rich Warren lives in Honolulu, Hawaii with his wife, Mika, daughter, Haruko, and his son, Kai. He is a software engineer, freelance writer and part time graduate student. When not playing on the beach, he is probably writing, coding or doing research on his MacBook Pro. You can reach Rich at rikiwarren@mac.com, check out his blog at http://freelancemadscience.blogspot.com/ or follow him at http://twitter.com/rikiwarren.

 
AAPL
$116.47
Apple Inc.
+0.16
MSFT
$47.98
Microsoft Corpora
-0.72
GOOG
$537.50
Google Inc.
+2.67

MacTech Search:
Community Search:

Software Updates via MacUpdate

Cobook 3.0.7 - Intelligent address book....
Cobook Contacts is an intuitive, engaging address book. Solve the problem of contact management with Cobook Contacts and its simple interface and powerful syncing and integration possibilities.... Read more
StatsBar 1.9 - Monitor system processes...
StatsBar gives you a comprehensive and detailed analysis of the following areas of your Mac: CPU usage Memory usage Disk usage Network and bandwidth usage Battery power and health (MacBooks only)... Read more
Cyberduck 4.6 - FTP and SFTP browser. (F...
Cyberduck is a robust FTP/FTP-TLS/SFTP browser for the Mac whose lack of visual clutter and cleverly intuitive features make it easy to use. Support for external editors and system technologies such... Read more
Maya 2015 - Professional 3D modeling and...
Maya is an award-winning software and powerful, integrated 3D modeling, animation, visual effects, and rendering solution. Because Maya is based on an open architecture, all your work can be scripted... Read more
Evernote 6.0.1 - Create searchable notes...
Evernote allows you to easily capture information in any environment using whatever device or platform you find most convenient, and makes this information accessible and searchable at anytime, from... Read more
calibre 2.11 - Complete e-library manage...
Calibre is a complete e-book library manager. Organize your collection, convert your books to multiple formats, and sync with all of your devices. Let Calibre be your multi-tasking digital... Read more
Herald 5.0.1 - Notification plugin for M...
Note: Versions 2.1.3 (for OS X 10.7), 3.0.6 (for OS X 10.8), and 4.0.8 (for OS X 10.9) are no longer supported by the developer. Herald is a notification plugin for Mail.app, Apple's Mac OS X email... Read more
Firetask 3.7 - Innovative task managemen...
Firetask uniquely combines the advantages of classical priority-and-due-date-based task management with GTD. Stay focused and on top of your commitments - Firetask's "Today" view shows all relevant... Read more
TechTool Pro 7.0.6 - Hard drive and syst...
TechTool Pro is now 7, and this is the most advanced version of the acclaimed Macintosh troubleshooting utility created in its 20-year history. Micromat has redeveloped TechTool Pro 7 to be fully 64... Read more
PhotoDesk 3.0.1 - Instagram client for p...
PhotoDesk lets you view, like, comment, and download Instagram pictures/videos! (NO Uploads! / Image Posting! Instagram forbids that! AND you *need* an *existing* Instagram account). But you can do... Read more

Latest Forum Discussions

See All

Ubisoft Gives Everyone Two New Ways to E...
Ubisoft Gives Everyone Two New Ways to Earn In-Game Stuff for Far Cry 4 Posted by Jessica Fisher on November 21st, 2014 [ permalink ] | Read more »
Golfinity – Tips, Tricks, Strategies, an...
Dig this: Would you like to know what we thought of being an infinite golfer? Check out our Golfinity review! Golfinity offers unlimited ways to test your skills at golf. Here are a few ways to make sure your score doesn’t get too high and your... | Read more »
Dark Hearts, The Sequel to Haunting Meli...
Dark Hearts, The Sequel to Haunting Melissa, is Available Now Posted by Jessica Fisher on November 21st, 2014 [ permalink ] Universal App - Designed for iPhone and iPad | Read more »
Meowza! Toyze Brings Talking Tom to Life...
Meowza! | Read more »
Square Enix Announces New Tactical RPG f...
Square Enix Announces New Tactical RPG for Mobile, Heavenstrike Rivals. Posted by Jessica Fisher on November 21st, 2014 [ permalink ] With their epic stories and gorgeous graphics, | Read more »
Quest for Revenge (Games)
Quest for Revenge 1.0.0 Device: iOS Universal Category: Games Price: $4.99, Version: 1.0.0 (iTunes) Description: The great Kingdom of the west has fallen. The gods ignore the prayers of the desperate. A dark warlord has extinguished... | Read more »
Threadz is a New Writing Adventure for Y...
Threadz is a New Writing Adventure for You and Your Friends Posted by Jessica Fisher on November 21st, 2014 [ permalink ] In the tradition of round-robin storytelling, | Read more »
SteelSeries Stratus XL Hardware Review
Made by: SteelSeries Price: $59.99 Hardware/iOS Integration Rating: 4 out of 5 stars Usability Rating: 4.5 out of 5 stars Reuse Value Rating: 4.25 out of 5 stars Build Quality Rating: 4.5 out of 5 stars Overall Rating: 4.31 out of 5 stars | Read more »
ACDSee (Photography)
ACDSee 1.0.0 Device: iOS iPhone Category: Photography Price: $1.99, Version: 1.0.0 (iTunes) Description: Capture, perfect, and share your photos with ACDSee. The ACDSee iPhone app combines an innovative camera, a powerful photo... | Read more »
ProTube for YouTube (Entertainment)
ProTube for YouTube 2.0.2 Device: iOS Universal Category: Entertainment Price: $1.99, Version: 2.0.2 (iTunes) Description: ProTube is the ultimate, fully featured YouTube app. With it's highly polished design, ProTube offers ad-free... | Read more »

Price Scanner via MacPrices.net

CEA Study Finds More People Recycling Electro...
A new study by the Consumer Electronics Association (CEA) finds that electronics recycling receives the continued and growing support of consumers. According to the CEA,s Recycling and Reuse Study,... Read more
15″ 2.2GHz Retina MacBook Pro on sale for $17...
 B&H Photo has the 2014 15″ 2.2GHz Retina MacBook Pro on sale today for $1749. Shipping is free, and B&H charges NY sales tax only. B&H will also include free copies of Parallels Desktop... Read more
27-inch 3.5GHz 5K iMac in stock today and on...
 B&H Photo has the new 27″ 3.5GHz 5K iMac in stock today and on sale for $2299 including free shipping plus NY sales tax only. Their price is $200 off MSRP, and it’s the lowest price available... Read more
21-inch 1.4GHz iMac on sale for $979, save $1...
B&H Photo has the new 21″ 1.4GHz iMac on sale for $979.99 including free shipping plus NY sales tax only. Their price is $120 off MSRP. B&H will also include free copies of Parallels Desktop... Read more
13-inch 1.4GHz/256GB MacBook Air on sale for...
B&H Photo has lowered their price on the 13″ 1.4GHz/256GB MacBook Air to $1059.99 including free shipping plus NY sales tax only. Their price is $140 off MSRP, and it’s the lowest price for this... Read more
Save up to $400 with Apple refurbished 2014 1...
The Apple Store has restocked Apple Certified Refurbished 2014 15″ Retina MacBook Pros for up to $400 off the cost of new models. An Apple one-year warranty is included with each model, and shipping... Read more
New 13-inch 1.4GHz MacBook Air on sale for $8...
 Adorama has the 2014 13″ 1.4GHz/128GB MacBook Air on sale for $899.99 including free shipping plus NY & NJ tax only. Their price is $100 off MSRP. B&H Photo has the 13″ 1.4GHz/128GB MacBook... Read more
Apple Expected to Reverse Nine-Month Tablet S...
Apple and Samsung combined accounted for 62 percent of the nearly 36 million branded tablets shipped in 3Q 2014, according to early vendor shipment share estimates from market intelligence firm ABI... Read more
Stratos: 30 Percent of US Smartphone Owners t...
Stratos, Inc., creator of the Bluetooth Connected Card Platform, has announced results from its 2014 Holiday Mobile Payments Survey. The consumer survey found that nearly one out of three (30 percent... Read more
2014 1.4GHz Mac mini on sale for $449, save $...
 B&H Photo has lowered their price on the new 1.4GHz Mac mini to $449.99 including free shipping plus NY tax only. Their price is $50 off MSRP, and it’s the lowest price available for this new... Read more

Jobs Board

*Apple* Solutions Consultant (ASC) - Apple (...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
*Apple* Solutions Consultant (ASC)- Retail S...
**Job Summary** The ASC is an Apple employee who serves as an Apple brand ambassador and influencer in a Reseller's store. The ASC's role is to grow Apple Read more
Project Manager, *Apple* Financial Services...
**Job Summary** Apple Financial Services (AFS) offers consumers, businesses and educational institutions ways to finance Apple purchases. We work with national and Read more
*Apple* Store Leader Program - College Gradu...
Job Description: Job Summary As an Apple Store Leader Program agent, you can continue your education as you major in the art of leadership at the Apple Store. You'll Read more
*Apple* Retail - Multiple Positions (US) - A...
Sales Specialist - Retail Customer Service and Sales Transform Apple Store visitors into loyal Apple customers. When customers enter the store, you're also the Read more
All contents are Copyright 1984-2011 by Xplain Corporation. All rights reserved. Theme designed by Icreon.