Tải bản đầy đủ (.pdf) (88 trang)

Praise for The iPhone Developer’s Cookbook 2nd phần 6 pptx

Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (11.45 MB, 88 trang )

ptg
411
Recipe: Tappable Overlays
}
- (void) action: (id) sender
{
// Add the subview
[self.view.window addSubview:self.overlay];
// Start the activity indicator
[(UIActivityIndicatorView *)[self.overlay viewWithTag:202]
startAnimating];
// Call the finish method, on delay
[self performSelector:@selector(finish) withObject:nil
afterDelay:3.0f];
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
Recipe: Tappable Overlays
Use custom overlays to present information as well as to establish modal sequences.
Recipe 10-9 creates a custom class called TappableOverlay.When tapped, this view
removes itself from the screen.This behavior makes it particularly suitable for showing
information in a way normally reserved for the UIAlertView class.
To use this class, create a view instance in Interface Builder.Add as many subviews and
design elements as needed. Use File > Read Class Files to import the TappableOverlay.h
header file.Then change the view class from UIView to TappableOverlay using the Iden-
tity Inspector (Command-4) and save the project.
To present the view, add it to the window just as Recipe 10-8 did.
- (void) action: (id) sender
{


// Add the overlay
[self.view.window addSubview:self.overlay];
}
No further programming is needed.The view waits for a user tap and when one is
received, it removes itself from the window.
Figure 10-8 shows a simple example of this kind of overlay; it displays “Tap to Con-
tinue.” It’s easy to see how you can extend this concept to show any kind of pertinent
information, creating a custom alternative to the UIAlertView class.As with Recipe 10-8,
this example does not use any orientation awareness.
ptg
412
Chapter 10 Alerting Users
Figure 10-8 This simple overlay dismisses itself
on receiving a user touch.
Recipe 10-9 Building a Custom Dismissible Alert View That Responds to User Taps
@interface TappableOverlay : UIView
@end
@implementation TappableOverlay
- (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
{
// Remove this view when it is touched
[self removeFromSuperview];
}
@end
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
Recipe: Orientable Scroll-Down Alerts
You can extend the modal concepts introduced in Recipe 10-8 to create a noninteractive

overlay that acts as a backdrop for a scroll-down alert. In Recipe 10-10, that overlay hosts
a view with an embedded button as shown in Figure 10-9.This view is presented and
ptg
413
Recipe: Orientable Scroll-Down Alerts
Figure 10-9 This modally presented message
scrolls down into view and is dismissed by tapping
the OKAY button.
dismissed via a pair of simple UIView animation blocks; the OKAY button triggers the
dismiss: method that scrolls the view offscreen.
The message view was created in Interface Builder as a standard
UIView. It’s added to the
overlay as a subview in the viewDidLoad method. Rather than adding and removing the
overlay from the main window, as Recipe 10-8 did, this recipe uses the overlay’s alpha
property to hide and show itself.
Unlike the previous two recipes, this recipe does pay attention to screen orientation. It
adapts its size and presentation to match the current iPhone orientation. It accomplishes
this in two ways. First, it applies an affine transform to the overlay when the orientation
changes. Second, it adjusts the overlay and message view frames before presentation,
matching the shape of the current window.
Although this example scrolls in from the top of the screen, it’s trivial to adapt the
math to have it scroll in from the sides (use the x origin rather than the y origin) or bot-
tom (add 320 or 480 to the view height).Alternatively, you might center the view and
animate its size so that it pops rather than slides into view.
Recipe 10-10 Creating an Orientable Scroll-Down Overlay
- (void) dismiss: (id) sender
{
ptg
414
Chapter 10 Alerting Users

// Animate the message view away
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3f];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
mvframe.origin = CGPointMake(0.0f, -300.0f);
self.messageView.frame = mvframe;
[UIView commitAnimations];
// Hide the overlay
[self.overlay performSelector:@selector(setAlpha) withObject:nil
afterDelay:0.3f];
}
- (void) action: (id) sender
{
// Adjust the overlay sizes based on the screen orientation
self.overlay.frame = self.view.window.frame;
mvframe.size.width = UIDeviceOrientationIsPortrait([[UIDevice
currentDevice] orientation]) ? 320.0f : 480.0f;
mvframe.origin = CGPointMake(0.0f, -mvframe.size.height);
self.messageView.frame = mvframe;
// Show the overlay
if (!self.overlay.superview)
[self.view.window addSubview:self.overlay];
self.overlay.alpha = 1.0f;
// Animate the message view into place
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.3f];
[UIView setAnimationCurve:UIViewAnimationCurveLinear];
mvframe.origin = CGPointMake(0.0f, 20.0f);
self.messageView.frame = mvframe;
[UIView commitAnimations];

}
- (void) viewDidLoad
{
self.navigationItem.rightBarButtonItem = BARBUTTON(@"Action",
@selector(action));
// Initialize the overlay and message view
self.overlay.alpha = 0.0f;
[self.overlay addSubview:self.messageView];
mvframe = messageView.frame;
mvframe.origin = CGPointMake(0.0f, -300.0f);
self.messageView.frame = mvframe;
ptg
415
Recipe: Using the Network Activity Indicator
Figure 10-10 The network activity indicator is
controlled by a UIApplication property.
}
- (BOOL)shouldAutorotateToInterfaceOrientation:
(UIInterfaceOrientation)interfaceOrientation
{
// Apply overlay transforms based on the orientation
if (interfaceOrientation ==
UIInterfaceOrientationPortraitUpsideDown)
self.overlay.transform = CGAffineTransformMakeRotation(M_PI);
else if (interfaceOrientation ==
UIInterfaceOrientationLandscapeLeft)
self.overlay.transform = CGAffineTransformMakeRotation(-M_PI /
2.0f);
else if (interfaceOrientation ==
UIInterfaceOrientationLandscapeRight)

self.overlay.transform = CGAffineTransformMakeRotation(M_PI /
2.0f);
else
self.overlay.transform = CGAffineTransformIdentity;
return YES;
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
Recipe: Using the Network Activity Indicator
When your application accesses the Internet from behind the scenes, it’s polite to let your
user know what’s going on. Rather than create a full-screen alert, Cocoa Touch provides a
simple application property that controls a spinning network activity indicator in the sta-
tus bar. Figure 10-10 shows this indicator in action, to the right of the WiFi indicator and
to the left of the current time display.
Recipe 10-11 demonstrates how to access this property, doing little more than toggling
the indicator on or off. In real-world use, you’ll likely perform your network activities on
a secondary thread. Make sure you perform this property change on the main thread so
the GUI can properly update itself.
ptg
416
Chapter 10 Alerting Users
Figure 10-11 The segmented control in Recipe 10-12 updates the applica-
tion badge number.
Recipe 10-11 Accessing the Status Bar’s Network Activity Indicator
- (void) action: (id) sender
{
// Toggle the network activity indicator
UIApplication *app = [UIApplication sharedApplication];

app.networkActivityIndicatorVisible =
!app.networkActivityIndicatorVisible;
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
Recipe: Badging Applications
If you’ve used the iPhone or iPod touch for any time, you’ve likely seen the small, red
badges that appear over applications on the home screen.These might indicate the num-
ber of missed phone calls or unread e-mails that have accumulated since the user last
opened Phone or Mail.
To set an application badge from within the program itself, set the applicationIcon
➥BadgeNumber property to an integer.To hide badges, set applicationIconBadgeNumber
to 0 (the number zero). Recipe 10-12 demonstrates how to read and set an application
badge. It matches the value of its segmented control to the most recently used badge
number.When users change the segmented control setting, it updates the badge accord-
ingly. Figure 10-11 shows this in action, displaying the interface within the application and
the badge number it generates.
Recipe 10-12 Reading and Updating Application Badges
@implementation TestBedViewController
- (void) updateBadge: (UISegmentedControl *) seg
{
// Set the badge number to the selected segment index
[UIApplication sharedApplication].applicationIconBadgeNumber =
seg.selectedSegmentIndex;
ptg
417
Recipe: Simple Audio Alerts
}

- (void) viewDidLoad
{
// Create the segment control for selecting the badge number
UISegmentedControl *seg = [[UISegmentedControl alloc]
initWithItems:[@"0 1 2 3 4 5" componentsSeparatedByString:
@" "]];
seg.segmentedControlStyle = UISegmentedControlStyleBar;
seg.selectedSegmentIndex = MIN([UIApplication
sharedApplication].applicationIconBadgeNumber, 5);
[seg addTarget:self action:@selector(updateBadge)
forControlEvents:UIControlEventValueChanged];
self.navigationItem.titleView = seg;
[seg release];
}
@end
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
Recipe: Simple Audio Alerts
Audio alerts “speak” directly to your users.They produce instant feedback—assuming
users are not hearing impaired. Fortunately,Apple built basic sound playback into the
Cocoa Touch SDK through System Audio services.This works very much like system
audio on a Macintosh.
The alternatives include using Audio Queue calls or AVAudioPlayer.Audio Queue
playback is expensive to program and involves much more complexity than simple alert
sounds need. In contrast, you can load and play system audio with just a few lines of code.
AVAudioPlayer also has its drawbacks. It interferes with iPod audio. In contrast, System
Audio can perform a sound without interrupting any music that’s currently playing,
although that may admittedly not be the result you’re looking for, as alerts can get lost in

the music.
Alert sounds work best when kept short, preferably 30 seconds or shorter according to
Apple. System Audio plays PCM and IMA audio only.That means limiting your sounds to
AIFF,WAV, and CAF formats.
System Sounds
To build a system sound, call AudioServicesCreateSystemSoundID with a file URL
pointing to the sound file.This call returns an initialized system sound object, which you
can then play at will. Just call AudioServicesPlaySystemSound with the sound object.
That single call does all the work.
ptg
418
Chapter 10 Alerting Users
AudioServicesPlaySystemSound(mySound);
The default implementation of system sounds allows them to be controlled by the Sound
Effects preference in Settings.When effects are disabled, the sound will not play.To over-
ride this preference and always play the sound, you can set a property flag as such.
// Identify it as a non UI Sound
AudioServicesCreateSystemSoundID(baseURL, &mysound);
AudioServicesPropertyID flag = 0; // 0 means always play
AudioServicesSetProperty(kAudioServicesPropertyIsUISound,
sizeof(SystemSoundID), &mysound,
sizeof(AudioServicesPropertyID), &flag);
When iPod audio is playing, the system sound generally plays back at the same volume, so
users may miss your alert. Consider using vibration in addition to or in place of music.You
can check the current playback state by testing as follows. Make sure you include
<MediaPlayer/MediaPlayer.h> and link to the MediaPlayer framework.
if ([MPMusicPlayerController iPodMusicPlayer].playbackState ==
MPMusicPlaybackStatePlaying)
Add an optional system sound completion callback to notify your program when a sound
finishes playing by calling AudioServicesAddSystemSoundCompletion. Unless you use

short sounds that are chained one after another, this is a step you can generally skip.
Clean up your sounds by calling AudioServicesDisposeSystemSoundID with the
sound in question.This frees the sound object and all its associated resources.
Note
To use these system sound services, make sure to include
AudioToolbox/AudioServices.h in your code and link to the Audio Toolbox framework.
Vibration
As with audio sounds, vibration immediately grabs a user’s attention.What’s more, vibra-
tion works for nearly all users, including those who are hearing or visually impaired.
Using the same System Audio services, you can vibrate as well as play a sound.All you
need is the following one-line call to accomplish it, as used in Recipe 10-13:
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
You cannot vary the vibration parameters. Each call produces a short one- to two-second
buzz. On platforms without vibration support (like the iPod touch), this call does
nothing—but will not produce an error.
Alerts
Audio Services provides a vibration/sound mashup called an alert sound, which is invoked
as follows.
AudioServicesPlayAlertSound(mySound);
ptg
419
Recipe: Simple Audio Alerts
This call, which is also demonstrated in Recipe 10-13, plays the requested sound and, pos-
sibly, vibrates or plays a second alert. On iPhones, when the user has set Settings > Sound >
Ring >Vibrate to ON, it vibrates the phone. Second generation and later iPod touch units
play the sound sans vibration (which is unavailable on those units) through the onboard
speaker. First generation iPod touches play a short alert melody in place of the sound on
the device speaker while playing the requested audio through to the headphones.
Delays
The first time you play back a system sound on the iPhone, you may encounter delays.

You may want to play a silent sound on application initialization to avoid a delay on sub-
sequent playback.
Note
When testing on iPhones, make sure you have not enabled the silent ringer switch on the
left side of the unit. This oversight has tripped up many iPhone developers. If your alert
sounds must always play, consider using the
AVAudioPlayer class, which is discussed in
Chapter 15, “Audio, Video, and MediaKit.”
Recipe 10-13 Playing Sounds, Alerts, and Vibrations Using Audio Services
@implementation TestBedViewController
- (void) playSound
{
if ([MPMusicPlayerController iPodMusicPlayer].playbackState ==
MPMusicPlaybackStatePlaying)
AudioServicesPlayAlertSound(mysound);
else
AudioServicesPlaySystemSound(mysound);
}
- (void) vibrate
{
AudioServicesPlaySystemSound (kSystemSoundID_Vibrate);
}
- (void) viewDidLoad
{
// create the sound
NSString *sndpath = [[NSBundle mainBundle]
pathForResource:@"basicsound" ofType:@"wav"];
CFURLRef baseURL = (CFURLRef)[NSURL fileURLWithPath:sndpath];
// Identify it as not a UI Sound
AudioServicesCreateSystemSoundID(baseURL, &mysound);

AudioServicesPropertyID flag = 0; // 0 means always play
AudioServicesSetProperty(kAudioServicesPropertyIsUISound,
ptg
420
Chapter 10 Alerting Users
sizeof(SystemSoundID), &mysound,
sizeof(AudioServicesPropertyID), &flag);
self.navigationItem.rightBarButtonItem = BARBUTTON(@"Sound",
@selector(playSound));
self.navigationItem.leftBarButtonItem = BARBUTTON(@"Vibrate",
@selector(vibrate));
}
-(void) dealloc
{
// Clean up
if (mysound) AudioServicesDisposeSystemSoundID(mysound);
[super dealloc];
}
@end
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 10 and open the project for this recipe.
One More Thing: Showing the Volume Alert
The iPhone offers a built-in alert that you can display to allow users to adjust the system
volume. Figure 10-12 shows this alert, which consists of a slider and a Done button.
Invoke this alert by issuing the following Media Player function.
- (void) action
{
// Show the Media Player volume settings alert

MPVolumeSettingsAlertShow();
}
Test whether this alert is visible by issuing MPVolumeSettingsAlertIsVisible().This
returns a Boolean value reflecting whether the alert is already onscreen. Hide the alert
with MPVolumeSettingsAlertHide(), which dismisses the alert regardless of whether the
user taps Done. For these functions to work, you must link to the MediaPlayer framework
and import the media player headers.
ptg
421
Summary
Figure 10-12 The Media Player class’s utility vol-
ume alert panel.
Summary
This chapter introduced ways to interact directly with your user.You learned how to
build alerts—visual, auditory, and tactile—that grab your user’s attention and can request
immediate feedback. Use these examples to enhance the interactive appeal of your pro-
grams and leverage some unique iPhone-only features. Here are a few thoughts to carry
away from this chapter:
n
Whenever any task will take a noticeable amount of time, be courteous to your
user and display some kind of progress feedback.The iPhone offers many ways to
do this, from heads-up displays to status bar indicators and beyond.You may need to
divert the non-GUI elements of your task to new thread to avoid blocking.
n
Alerts take users into the moment.They’re designed to elicit responses while com-
municating information.And, as you saw in this chapter, they’re almost insanely
customizable. It’s possible to build entire applications around the simple
UIAlertView.
n
Don’t be afraid of the run loop.A modal response from an alert or action sheet lets

you poll users for immediate choices without being dependent on asynchronous
callbacks.
ptg
422
Chapter 10 Alerting Users
n
If blue colored system-supplied features do not match your application design
needs, skip them.You can easily build your own alerts and menus using UIView
instances and animation.
n
Audio feedback including beeps and vibration can enhance your programs and
make your interaction richer. Using system sound calls means that your sounds play
nicely with iPod functionality and won’t ruin the ongoing listening experience.At
the same time, don’t be obnoxious. Use alert sounds sparingly and meaningfully to
avoid annoying your users.
ptg
11
Creating and Managing
Table Views
T
ables provide a scrolling list-based interaction class that works particularly well on a
small, cramped device. Many if not most apps that ship natively with the iPhone and
iPod touch center on tables, including Contacts, Settings, iPod,YouTube, Stocks, and
Weather.The iPhone’s limited screen size makes tables, with their scrolling and individual
item selection, an ideal way to deliver information and content in simple, easy-to-
manipulate form. In this chapter, you discover how iPhone tables work, what kinds of
tables are available to you as a developer, and how you can use table features in your own
programs.
Introducing UITableView and
UITableViewController

The standard iPhone table consists of a simple scrolling list of individual cells, providing a
manipulatable data index. Users may scroll or flick their way up and down until they find
an item they want to interact with.Then, they can work with that item independently of
other rows. On the iPhone, tables are ubiquitous. Nearly every standard software package
uses them, and they form the core of many third-party applications, too. In this section,
you discover how tables function and what elements you need to bring together to create
your own.
The iPhone SDK supports several kinds of tables, many of which are implemented as
flavors of the UITableView class. In addition to the standard scrolling list of cells, which
provides the most generic table implementation, you can create several specialized tables.
These include the kind of tables you see in the Preferences application, with their blue-
gray background and rounded cell edges; tables with sections and an index like the ones
used in the Contacts application; and related classes of wheeled tables, like those used to
set appointment dates and alarms. No matter what type of table you use, they all work in
the same general way.They contain cells provided from a data source and respond to user
interactions by calling well-defined delegate methods.
ptg
424
Chapter 11 Creating and Managing Table Views
The UITableViewController class derives from the UIViewController class. Like its
parent class, it helps you build onscreen presentations with minimal programming and
maximum convenience.The UITableViewController class greatly simplifies the process
of creating a UITableView, reducing or eliminating the repetitive steps required for work-
ing directly with table instances. UITableViewController handles the fussy details for the
table view layout and provides table-specific convenience by adding a local tableView
instance variable and automatic table protocol support for delegates and data sources.
Creating the Table
To implement tables, you must define three key elements: how the table is laid out, the
kinds of things that are used to fill the table, and how the table reacts to user interaction.
Specify these elements by adding descriptions and methods to your application.You cre-

ate the visual layout when building your views, you define a data source that feeds table
cells on demand, and you implement delegate methods that respond to user interactions
such as row-selection changes.
Laying Out the View
UITableViews instances are, as the name suggests, views.They present interactive tables
on the iPhone screen.The UITableView class inherits from the UIScrollView class.This
inheritance provides the up and down scrolling capabilities used by the table. Like other
views, UITableView instances define their boundaries through frames, and they can be
children or parents of other views.To create a table view, you allocate it, initialize it with a
frame just like any other view, and then add all the bookkeeping details by assigning data
source and delegate objects.
UITableViewControllers take care of the layout work for you.The
UITableViewController class creates a standard UIViewController and populates it
with a single UITableView, setting its frame to allow for any navigation bars or toolbars.
You may access that table view via the tableView instance variable.
One important note:When subclassing UITableViewController, if you define a
loadView method, be sure to call its superclass’s implementation—that is:
- (void) loadView
{
[super loadView];
the rest of your method
}
Doing this ensures that the table view is properly set up, while letting you add
custom features in the subclass such as navigation item buttons. If you create your
UITableViewController using Interface Builder, you do not have to add
any special calls to loadView.
ptg
425
Introducing UITableView and UITableViewController
Assigning a Data Source

UITableView instances rely on an external source to feed either new or existing table
cells on demand.This external source is called a data source and refers to the object whose
responsibility it is to return a cell to a table’s query.
Data sources provide table cells based on an index path. Index paths, objects of the
NSIndexPath class, describe the path through a data tree to a particular node, namely
their section and their row.Although many simple tables only use one section, tables can
use sections to split data into logical groups.A UITableView instance uses index paths to
specify a section and the row within that section.
It’s the data source’s job to connect that path to a concrete UITableViewCell instance
and return that cell on demand.You can create an index path by supplying the section
and row:
myIndexPath = [NSIndexPath indexPathForRow:5 inSection:0];
Recover those values by using the row and section properties of the index path object.
The iPhone SDK provides a built-in mechanism for reusing table cells.When cells
scroll off the table and out of view, the table can cache them into a reuse queue.You can
tag cells for reuse and then pop them off that queue as needed.This saves memory and
provides a fast, efficient way to feed cells when users scroll quickly through long lists
onscreen. Recipe 11-8 looks at cell reuse in more detail.
You’re not limited to single cell types either.The following snippet chooses which of
two kinds of cells to request from the reusable cell queue. Default cells provide a single
label; subtitle cells add a second.The identifier is arbitrary, as defined by the developer.
UITableViewCell *cell;
UITableViewCellStyle style;
NSString *identifier;
if (item.notes)
{
style = UITableViewCellStyleSubtitle;
identifier = @"notescell";
}
else

{
style = UITableViewCellStyleDefault;
identifier = @"basecell";
}
cell = [aTableView dequeueReusableCellWithIdentifier:identifier];
if (!cell)
cell = [[[UITableViewCell alloc] initWithStyle:style
reuseIdentifier:identifier] autorelease];
ptg
426
Chapter 11 Creating and Managing Table Views
Use the table’s dataSource property to assign an object to a table as its data source.That
object must implement the UITableViewDataSource protocol. Most typically, the
UITableViewController that owns the table view acts as the data source for that view.
When working with UITableViewController subclasses, you need not declare the pro-
tocol as the parent class implicitly supports that protocol and automatically assigns the
controller as the data source.
After assigning a data source, load your table up with its cells by implementing the
tableView:cellForRowAtIndexPath: method. On calling the table’s reloadData
method, the table starts querying its data source to load the actual onscreen cells into your
table.You can also call reloadData at any time to force the table to reload its contents.
Assigning a Delegate
Like many other Cocoa Touch interaction objects,
UITableView instances use delegates to
respond to user interactions and implement a meaningful response.Your table’s delegate
can respond to events like the table scrolling or row selection changes. Delegation tells the
table to hand off responsibility for reacting to these interactions to the object you specify,
typically the UITableViewController object that owns the table view.
If you’re working directly with a UITableView, use the standard setDelegate:
method to set your table’s delegate.The delegate must implement the UITableViewDelegate

protocol.When classes implement a delegate protocol, you add a declaration within the
class header file. See Chapter 3,“Objective-C Boot Camp,” for an explanation of declar-
ing protocols.
When working with UITableViewController, omit the setDelegate: method and
protocol assignment.That class automatically handles this.A full set of delegate methods is
listed in the Apple SDK documentation, and the most basic ones are discussed in this
chapter.
Note
UITableView instances provide notifications in addition to delegate method calls. Notifica-
tions enable different threads of your application to communicate with each other by broad-
casting updates via the default
NSNotificationCenter. You can subscribe your
application to these notifications using standard
NSNotificationCenter observers to find
out when the table states change. With the 3.0 SDK, the only official table notification is
UITableViewSelectionDidChangeNotification.
Recipe: Implementing a Very Basic Table
The UITableViewController class embeds a UITableView into a UIViewController
object that manages its table view.This view is accessed via the tableView property.These
controllers automatically set the data source and delegate methods for the table view to
itself. So it’s really a plug-and-play situation. For a really basic table, all you need to bring
to the table are some data and a few data source functions that feed cells and report the
number of rows and sections.
ptg
427
Recipe: Implementing a Very Basic Table
Figure 11-1 It’s easy to fill a UITableView
with cells based on any array of strings. This table
presents the font family list from the UIFont
class. When tapped, the chosen item updates the

font on the navigation bar at the top.
Populating a Table
Pretty much any array of strings can be used to set up and populate a table. Recipe 11-1
leverages the UIFont class’s capability to list available system fonts, that is, a handy list of
strings. A call to [UIFont familyNames] returns an array populated with those font
names.This recipe creates a basic table based on those font names.
Figure 11-1 shows the interface produced by this code, as run on the iPhone simulator.
Be aware that running this application on the simulator produces an artificially long set of
fonts.That’s because the list is based on the available fonts from the Macintosh running
the SDK rather than the fonts on the iPhone itself.
Data Source Methods
To display a table, every table data source must implement three core methods.These
methods define how the table is structured and provide contents for the table:
n
numberOfSectionsInTableView—Tables can display their data in sections
or as a single list. For simple tables, return 1.This indicates that the entire table should
be presented as one single list. For sectioned lists, return a value of 2 or higher.
ptg
428
Chapter 11 Creating and Managing Table Views
n
tableView:numberOfRowsInSection—This method returns the number
of rows for each section.When working with simple lists, return the number of
rows for the entire table here. For more complex lists, you’ll want to provide a way
to report back per section. Section ordering starts with 0.
n
tableView: cellForRowAtIndexPath:—This method returns a cell to
the calling table. Use the index path’s row and section properties to determine
which cell to provide and make sure to take advantage of reusable cells where possi-
ble to minimize memory overhead.

Reusing Cells
One of the ways the iPhone conserves memory is by reusing cells.You can assign an iden-
tifier string to each cell.This specifies what kind of cell it is, and when that cell scrolls off-
screen allows that cell to be recovered for reuse. Use different IDs for different kinds of
cells. For simple tables, a single identifier does the job. In the case of Recipe 11-1, it is
@
"
BaseCell
"
.The strings are arbitrary. Define them the way you want, but when using
multiple cell types keep the names meaningful.The discussion for Recipe 11-8, which fol-
lows later in this chapter, explores cell reuse.
Before allocating a new cell, always check whether a reusable cell is available. If your
table returns nil from a request to dequeueReusableCellWithIdentifier:, you need to
allocate a new cell.
If the method returns a cell, update that cell with the information that’s meaningful for
the current row and section indices.You do not need to add cells to the reuse queue.
Cocoa Touch handles all those details for you.
Font Table Sample
Recipe 11-1 demonstrates how to build a simple list-based table. It creates a table and fills
that table with all available font families.When tapped, the view controller assigns that
font to the label in the navigation bar at the top of the screen and prints a list of available
fonts for that family out to the debugger console.This behavior is defined in the
tableView:didSelectRowAtIndexPath: delegate method, which is called when a user
taps a row.
Using the UITableViewController as a delegate is a good choice because the table’s
user interactions affect its views. If you’d rather use another delegate, call setDelegate:
with that object to override the standard UITableViewController settings.
Apple made several big changes in table view cells between the 2.x and 3.x SDKs.
Prior to 3.0, you could set a cell’s text and image properties directly. Starting with the 3.0

SDK,Apple introduced the textLabel, detailLabel, and imageView properties. Each
property now points to an actual UI object (two UILabels and a UIImageView), offering
direct access to each object.
ptg
429
Recipe: Implementing a Very Basic Table
Note
Tables enable you to set the color for the selected cell by choosing between a blue or gray
overlay. Set the
selectionStyle property to either UITableViewCellSelection
➥StyleBlue or UITableViewCellSelectionStyleGray. If you’d rather not show a selec-
tion, use
UITableViewCellSelectionStyleNone. The cell can still be selected, but the
overlay color will not display.
Recipe 11-1 Building a Basic Table
#define MAINLABEL ((UILabel *)self.navigationItem.titleView)
@interface TableListViewController : UITableViewController
@end
@implementation TableListViewController
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
{
// One section in this simple table
return 1;
}
- (NSInteger)tableView:(UITableView *)aTableView
numberOfRowsInSection:(NSInteger)section
{
// Number of rows in use
return [UIFont familyNames].count;
}

- (UITableViewCell *)tableView:(UITableView *)tView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
// Attempt to dequeue a cell. If this is not possible, create one
UITableViewCellStyle style = UITableViewCellStyleDefault;
UITableViewCell *cell = [tView
dequeueReusableCellWithIdentifier:@"BaseCell"];
if (!cell)
cell = [[[UITableViewCell alloc] initWithStyle:style
reuseIdentifier:@"BaseCell"] autorelease];
// Set the cell text
cell.textLabel.text = [[UIFont familyNames]
objectAtIndex:indexPath.row];
return cell;
}
- (void)tableView:(UITableView *)tableView
ptg
430
Chapter 11 Creating and Managing Table Views
didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
// React to cell selection by updating the title view text
NSString *font = [[UIFont familyNames]
objectAtIndex:indexPath.row];
[MAINLABEL setText:font];
[MAINLABEL setFont:[UIFont fontWithName:font size:18.0f]];
}
- (void) loadView
{
// Add a custom label to the navigation bar’s title view

[super loadView];
self.navigationItem.titleView = [[[UILabel alloc]
initWithFrame:CGRectMake(0.0f, 0.0f, 200.0f, 30.0f)]
autorelease];
[MAINLABEL setBackgroundColor:[UIColor clearColor]];
[MAINLABEL setTextColor:[UIColor whiteColor]];
[MAINLABEL setTextAlignment:UITextAlignmentCenter];
}
@end
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 11 and open the project for this recipe.
Recipe: Changing a Table’s Background Color
To use a color for your table’s background other than white, use the table view’s
backgroundColor property, as demonstrated in Recipe 11-2. Individual cells inherit this
color, producing a table whose components all show that color. Make sure that you
choose a cell text color that compliments any table background color. For a dark purple
background, as defined and used in this recipe, a strong white contrasts nicely.
Unfortunately, you cannot change individual cell backgrounds directly.That is to say,
you can, by setting the cell’s backgroundColor property, but nearly all the color change
will happen behind label views.The labels block the cell’s background, obscuring it from
view.You will see few, if any, changes to the cell. Set the table style to
UITableViewStyleGrouped for the most (i.e.,“not much”) background visibility.
Recipe 11-2 Changing the Background Color for a Table
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
// Create Table View Controller and set its background color
ptg
431

Recipe: Changing a Table’s Background Color
TableListViewController *tlvc = [[TableListViewController alloc]
init];
tlvc.tableView.backgroundColor = COOKBOOK_PURPLE_COLOR;
// Initialize Navigation Controller
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:tlvc];
nav.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
// Create main window
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen
mainScreen] bounds]];
[window addSubview:nav.view];
[window makeKeyAndVisible];
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 11 and open the project for this recipe.
Updating the Background Color to Reflect the Degree of Scrolling
Because UITableViews are a subclass of the UIScrollView class, you can adapt your table
background color to the degree that a user has scrolled down the table. For example, you
might lighten or darken the background color. Use the percentage of distance as a multi-
plication factor for the color components used to tint the background.
In their default state, all UITableViewController instances are automatically set as
UIScrollView delegates. No further work is needed before adding the following
UIScrollViewDelegate method to your UITableViewController implementation.The
following code calculates background color saturation from the current table offset.
- (void) scrollViewDidScroll: (UIScrollView *) sv
{
float percent = sv.contentOffset.y / sv.contentSize.height;

percent = 0.5 + (MAX(MIN(1.0f, percent), 0.0f) / 2.0f);
self.tableView.backgroundColor = [UIColor
colorWithRed:percent * 0.20392 green:percent * 0.19607
blue:percent * 0.61176 alpha: 1.0f];
}
Here are a few things to note about background color updates. First, if you don’t enable
bouncing (i.e., allowing the table to bounce past the content edges and then move back),
decrease the divisor by the height of the table. Second, make sure you set your initial
colors when setting up your table. Otherwise, the color will “jump” the first time the user
ptg
432
Chapter 11 Creating and Managing Table Views
Figure 11-2 Combine a clear table background
color with a backsplash to create a table that
scrolls over an image.
touches the table. Finally, although this approach is not computationally overwhelming,
it does require constant screen updates and should be avoided for processor-heavy
applications.
Recipe: Creating a Table Image Backsplash
Recipe 11-3 expands the background color idea presented in Recipe 11-2 to create a
table view with an image backdrop. Instead of coloring the background to a solid hue, this
recipe uses a clear color with an alpha level of 0. By adding the backdrop to the applica-
tion window before adding the table view, the image bleeds through the table, as shown in
Figure 11-2.
The table scrolls over the image, which remains static behind it. Keep the imagery relevant
(for example, a corporate logo) and desaturated or otherwise lightened enough that it will
not interfere with the table’s text presentation. Use a text color that contrasts well with the
background image.
Recipe 11-3 Scrolling a Table over a Static Image
- (void)applicationDidFinishLaunching:(UIApplication *)application

{
ptg
433
Recipe: Exploring Cell Types
// Create Table View Controller with a clear background
TableListViewController *tlvc = [[TableListViewController alloc]
init];
tlvc.tableView.backgroundColor = [UIColor clearColor];
// Initialize Navigation Controller
UINavigationController *nav = [[UINavigationController alloc]
initWithRootViewController:tlvc];
nav.navigationBar.tintColor = COOKBOOK_PURPLE_COLOR;
// Load in the backsplash image into a view
UIImageView *iv = [[[UIImageView alloc] initWithImage:[UIImage
imageNamed:@"Backsplash.png"]] autorelease];
// Create main window
UIWindow *window = [[UIWindow alloc] initWithFrame:[[UIScreen
mainScreen] bounds]];
[window addSubview:iv];
[window addSubview:nav.view];
[window makeKeyAndVisible];
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 11 and open the project for this recipe.
Recipe: Exploring Cell Types
The iPhone offers four kinds of base table view cells.These types, which are shown in
Figure 11-3, provide basic utilitarian cell implementations. Each of these cell styles is new
to the 3.0 SDK (although the default style was used in 2.x, it has a new style name con-

stant) and represents a new way of creating and interacting with table cells.
Before 3.0, you assigned a cell’s text directly. Now cells provide both a textLabel and
a detailTextLabel property, which offer access to the labels themselves.With direct
label access, you can set each label’s text traits as desired. Here is a round-up of the four
new styles:
n
UITableViewCellStyleDefault—This cell offers a single left-aligned text
label and an optional image.When images are used, the label is pushed to the right,
decreasing the amount of space available for text.You can access and modify the
detailTextLabel, but it is not shown onscreen.
n
UITableViewCellStyleSubtitle—This cell, which is used in the iPod
application, pushes the standard text label up a bit to make way for the smaller detail
label beneath it.The detail label displays in gray. Like the default cell, the subtitle cell
offers an optional image.
ptg
434
Chapter 11 Creating and Managing Table Views
Figure 11-3 Cocoa Touch provides four standard
cell types, some of which support optional images.
n
UITableViewCellStyleValue1—This cell style, seen in the Settings appli-
cation, offers a large black primary label on the left side of the cell and a slightly
smaller, blue subtitle detail label to its right.This cell does not support images.
n
UITableViewCellStyleValue2—The Phone/Contacts application uses this
kind of cell, which consists of a small blue primary label on the left and a small
black subtitle detail label to its right.The small width of the primary label means
that most text will be cut off by an ellipsis.This cell does not support images.
Recipe 11-4 shows the code that created the cells of Figure 11-3. It labels each cell with

the type in use and uses that same text as the reuse identifier. Images are added to all cells
past the first four, demonstrating that only the default and subtitle presentations support
image display.
Recipe 11-4 Creating Various Table Cell Styles
- (UITableViewCell *)tableView:(UITableView *)tView
cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCellStyle style;
NSString *cellType;
// Choose the cell style and tag
switch (indexPath.row % 4)
ptg
435
Recipe: Building Custom Cells in Interface Builder
{
case 0:
style = UITableViewCellStyleDefault;
cellType = @"Default Style";
break;
case 1:
style = UITableViewCellStyleSubtitle;
cellType = @"Subtitle Style";
break;
case 2:
style = UITableViewCellStyleValue1;
cellType = @"Value1 Style";
break;
case 3:
style = UITableViewCellStyleValue2;
cellType = @"Value2 Style";

break;
}
// Dequeue a cell if possible, if not, create one.
UITableViewCell *cell = [tView
dequeueReusableCellWithIdentifier:cellType];
if (!cell)
cell = [[[UITableViewCell alloc] initWithStyle:style
reuseIdentifier:cellType] autorelease];
// Add images to all cells after the first four
if (indexPath.row > 3)
cell.imageView.image = [UIImage imageNamed:@"icon.png"];
// Set the cell text.
cell.textLabel.text = cellType;
cell.detailTextLabel.text = @"Subtitle text";
return cell;
}
Get This Recipe’s Code
To get the code used for this recipe, go to or
if you’ve downloaded the disk image containing all of the sample code from the book, go to
the folder for Chapter 11 and open the project for this recipe.
Recipe: Building Custom Cells in Interface Builder
Interface Builder makes it easy to create custom UITableViewCell instances without
subclassing.You can build your cells directly in IB and load them in your code, which is
exactly what Recipe 11-5 does.The big problem about using IB is that your custom

×