MOBILE

iPhone Application Development : Getting the User’s Attention - Generating Alerts

2/19/2011 3:46:51 PM
Sometimes users need to be informed of changes when an application is running. More than just a change in the current view is required when an internal error event occurs (such as low-memory condition or a dropped network connection), for example, or upon completion of a long-running activity. Enter the UIAlertView class.

The UIAlertView class creates a simple modal alert window that presents a user with a message and a few option buttons (see Figure 1).

Figure 1. Implement UIAlertView to display simple messages to the user.


What Does Modal Mean?

Modal UI elements require the user to interact with them (usually, to push a button) before the user can do anything else. They are typically layered on top of other windows and block all other interface actions while visible.


Displaying a Simple Alert

In the preceding section, you created a simple project (GettingAttention) with several buttons that we’ll use to activate the different notification events. The first button, Alert Me!, should be connected to a method stub called doAlert in GettingAttentionViewController.m. In this first exercise, we write an implementation of doAlert that displays an alert message with a single button that the user can push to dismiss the dialog.

Edit GettingAttentionViewController.m and enter the code shown in Listing 1 for doAlert.

Listing 1.
 1: -(IBAction)doAlert:(id)sender {
2: UIAlertView *alertDialog;
3: alertDialog = [[UIAlertView alloc]
4: initWithTitle: @"Alert Button Selected"
5: message:@"I need your attention NOW!"
6: delegate: nil
7: cancelButtonTitle: @"Ok"
8: otherButtonTitles: nil];
9: [alertDialog show];
10: [alertDialog release];
11: }

In lines 2 and 3, we declare and instantiate our instance of UIAlertView with a variable called alertDialog. As you can see, the convenient initialization method of the alert view does almost all the work for us. Let’s review the parameters:

initWithTitle: Initializes the view and sets the title that will appear at the top of the alert dialog box.

message: Sets the string that will appear in the content area of the dialog box.

delegate: Contains the object that will serve as the delegate to the alert. Initially, we don’t need any actions to be performed after the user dismisses the alert, so we can set this to nil.

cancelButtonTitle: Sets the string shown in the default button for the alert.

otherButtonTitles: Adds an additional button to the alert. We’re starting with a single-button alert, so this is set to nil.

After alertDialog has been initialized, the next step is to show it by using (surprise!) the show method, as shown in line 9. Finally, as soon as we’re done with the alert, we can release it, as seen in line 10.

By the Way

If you prefer to set the alert message and buttons independent of the initialization, the UIAlertView class includes properties for setting the text labels (message, title) individually and methods for adding buttons (addButtonWithTitle).


Figure 2 shows the outcome of these settings.

Figure 2. In its simplest form, an alert view displays a message and button to dismiss it.


By the Way

An alert doesn’t have to be a single-use object. If you’re going to be using an alert repeatedly, create an instance when your view is loaded and show it as needed—but remember to release the object when you’re finished using it!


Creating Multi-Option Alerts

An alert with a single button is easy to implement because there is no additional logic to program. The user taps the button, the alert is dismissed, and execution continues as normal. If you need to add additional buttons, however, your application needs to be able to identify the button pressed and react appropriately.

In addition to the single-button alert that you just created, there are two additional configurations to learn. The difference between them is how many buttons you’re asking the alert to display. A two-button alert places buttons side by side. When more than two buttons are added, the buttons are stacked, as you’ll soon see.

Adding Buttons

Creating an alert with multiple buttons is simple: We just take advantage of the otherButtonTitles parameter of the initialization convenience method. Instead of setting to nil, provide a list of strings terminated by nil that should be used as the additional button names. The cancel button will always be displayed on the left in a two-button scenario or at the bottom of a longer button list.

Did you Know?

At most, an alert view can display five buttons (including the button designated as the “cancel” button) simultaneously. Attempting to add more may result in some very unusual onscreen effects, such as display of clipped/partial buttons.


For example, to expand the previous example to include two new buttons, the initialization can be changed as follows:

alertDialog = [[UIAlertView alloc]
initWithTitle: @"Alert Button Selected"
message:@"I need your attention NOW!"
delegate: nil
cancelButtonTitle: @"Ok"
otherButtonTitles: @"Maybe Later", @"Never", nil];

Write an updated version of the doAlert method within the doMultiButtonAlert method stub created earlier. Listing 2 shows the final code.

Listing 2.
-(IBAction)doMultiButtonAlert:(id)sender {
UIAlertView *alertDialog;

alertDialog = [[UIAlertView alloc]
initWithTitle: @"Alert Button Selected"
message:@"I need your attention NOW!"
delegate: nil
cancelButtonTitle: @"Ok"
otherButtonTitles: @"Maybe Later", @"Never", nil];

[alertDialog show];
[alertDialog release];
}

Pressing the Alert with Buttons! button should now open the alert view displayed in Figure 3.

Figure 3. Add additional buttons during initialization of the alert view.


Try pushing one of the buttons. The alert view is dismissed. Push another? The same thing happens. All the buttons do exactly the same thing—absolutely nothing. Although this behavior was fine with a single button, it’s not going to be very useful with our current configuration.

Responding to a Button Press with the Alert View Delegate Protocol

When I first started using Objective-C, I found the terminology painful. It seemed that no matter how easy a concept was to understand, it was surrounded with language that made it appear harder than it was. A protocol, in my opinion, is one of these things.

Protocols define a collection of methods that perform a task. To provide advanced functionality, some classes, such as UIAlertView, require you to implement methods defined in a related protocol. Some methods are required and others are optional; it just depends on the features you need.

To make the full use of an alert view, an additional protocol method must added to one of our classes. We’ll be using our main application’s view controller class for this purpose, but in larger projects it may be a completely separate class. The choice is entirely up to you. A class that implements a protocol is said to “conform” to that protocol.

To identify the button that was pressed in a multi-option alert, for example, our GettingAttentionViewController should conform to the UIAlertViewDelegate protocol and implement the alertView:clickedButtonAtIndex: method.

Edit the GettingAttentionViewController.h interface file to declare that the class will be conforming to the necessary protocol by modifying the @interface line as follows:

@interface GettingAttentionViewController : UIViewController
<UIAlertViewDelegate> {

Next, update the initialization code of the alert view in doMultiButtonAlert so that the delegate is pointed to the object that implements the UIAlertViewDelegate. Because this is the same object (the view controller) that is creating the alert, we can just use self:

alertDialog = [[UIAlertView alloc]
initWithTitle: @"Alert Button Selected"
message:@"I need your attention NOW!"
delegate: self
cancelButtonTitle: @"Ok"
otherButtonTitles: @"Maybe Later", @"Never", nil];

The alertView:clickedButtonAtIndex method that we write next will receive the index of the button that was pushed and give us the opportunity to act on it. To make this easier, we can take advantage of the UIAlertView instance method buttonTitleAtIndex. This method will return the string title of a button from its index, eliminating the need to keep track of which index value corresponds to which button.

Add the code in Listing 3 to GettingAttentionViewController.m to display a message when a button is pressed.

Listing 3.
 1: - (void)alertView:(UIAlertView *)alertView
2: clickedButtonAtIndex:(NSInteger)buttonIndex {
3: NSString *buttonTitle=[alertView buttonTitleAtIndex:buttonIndex];
4: if ([buttonTitle isEqualToString:@"Maybe Later"]) {
5: userOutput.text=@"Clicked 'Maybe Later'";
6: } else if ([buttonTitle isEqualToString:@"Never"]) {
7: userOutput.text=@"Clicked 'Never'";
8: } else {
9: userOutput.text=@"Clicked 'Ok'";
10: }
11: }

To start, in line 3, buttonTitle is set to the title of the button that was clicked. Lines 4 through 10 test the value of buttonTitle against the names of the buttons that we initialized when creating the alert view. If a match is found, the userOutput label in the view is updated to something appropriate.

This is just one way to implement the button handler for your alert. In some cases (such as dynamically generated button labels), it may be more appropriate to work directly with the button index values. You may also want to consider defining constants for button labels.

Watch Out!

Don’t assume that application processing stops when the alert window is on the screen! Your code will continue to execute after you show the alert. You may even want to take advantage of this by using the UIAlertView instance method dismissWithClickedButtonIndex: to remove the alert from the screen if the user does not respond within a certain length of time.


Adding Fields to Alerts

Although buttons can be used to generate user input from an alert, you might have noticed that some applications actually present text fields within an alert box. The App Store, for example, prompts for your iTunes password before it starts downloading a new app.

To add fields to your alert dialogs, you need to be a bit “sneaky.” There isn’t a simple “add text field” option, but you can take advantage of the method addSubView to add one view to another. This method is common to all subclasses of an UIView, which includes the alert views we need to modify and the text field we need to display. In short, we will manually create a field and position it within the alert view. Because the alert view doesn’t “know” it’s going to be there, we can use the alert view’s message text to create space for the field. Sound bizarre? It is, but it isn’t difficult.

Let’s start by providing a place to store and reference the field.

Adding the Text Field Instance Variable

We don’t have Interface Builder around to drag a field into an alert view, so we need to declare, allocate, and initialize it manually. Open the GettingAttentionViewController.h file and modify it to include a UITextField named userInput. Be sure to include a @property directive for it, too, as shown in Listing 4

Listing 4.
#import <UIKit/UIKit.h>

@interface GettingAttentionViewController :
UIViewController <UIAlertViewDelegate> {
IBOutlet UILabel *userOutput;
UITextField *userInput;
}

@property (retain, nonatomic) IBOutlet UILabel *userOutput;
@property (retain, nonatomic) UITextField *userInput;

- (IBAction)doAlert:(id)sender;
- (IBAction)doMultiButtonAlert:(id)sender;
- (IBAction)doAlertInput:(id)sender;
- (IBAction)doActionSheet:(id)sender;
- (IBAction)doSound:(id)sender;
- (IBAction)doAlertSound:(id)sender;
- (IBAction)doVibration:(id)sender;

@end

Next, open the implementation file (GettingAttentionViewController.m) and add a @synthesize line for userInput immediately following the userOutput @synthesize line:

@synthesize userInput;

Finally, update the dealloc method to release userInput when the application is completed:

- (void)dealloc {
[userInput release];
[userOutput release];
[super dealloc];
}

Now we’re ready to build the doAlertInput method.

Adding a Text Field Subview

The steps that we take to add a field to an alert may seem unusually convoluted, but, broken down, they’re easy to understand. First, we initialize the alert, making sure that it includes enough space in the view (by adding a message) so that we can add a field over top of it. Then, we allocate and initialize a new text field (userInput) and set its color to white so that we can see it on top of the alert view. Finally, we add the text field to the alert using the addSubView method to position it over top of where the alert’s message line would appear.

Enter the doAlertInput method in GettingAttentionViewController.m using the code in Listing 5.

Listing 5.
 1: -(IBAction)doAlertInput:(id)sender {
2: UIAlertView *alertDialog;
3:
4: alertDialog = [[UIAlertView alloc]
5: initWithTitle: @"Please Enter Your Email Address!"
6: message:@"You won't see me"
7: delegate: self
8: cancelButtonTitle: @"Ok"
9: otherButtonTitles: nil];
10:
11: userInput=[[UITextField alloc] initWithFrame:
12: CGRectMake(12.0, 70.0, 260.0, 25.0)];
13:
14: [userInput setBackgroundColor:[UIColor whiteColor]];
15:
16: [alertDialog addSubview:userInput];
17: [alertDialog show];
18: [alertDialog release];
19: }

The beginning and end of this method should look familiar. It’s identical to doAlert, with the exception of the delegate being set to self (more on that a little later). The differences are in lines 11–16.

Lines 11–12 allocate, initialize, and assign a new UITextField instance to the userInput field. The initWithFrame method initializes the object with a rectangle returned by the CGRectMake() function. The values of 12.0, 70.0, 260.0, and 25.0 indicate that the field will be located 12.0 points from the left side of the view it is placed within and 70.0 points from the top. It will be 260.0 points wide and 25.0 points tall. Where did these values come from? Experimentation! These are the values that will correctly position the field over top of the message “You won’t see me.”

Line 14 sets the background of the text field to white.

Line 16 adds the field to the alert view using the addSubView method.

You should now be able to Build and Run the GettingAttention application, click the I Need Input! button, and see an alert with an input field, as demonstrated in Figure 4.

Figure 4. Add fields to your alert views using the addSubView method.


All that remains is being able to do something with the contents of the field—and that part is easy!

Accessing the Text Field

To access the input the user provided in the alert view, we just need to read the text property of userInput. Where do we do this? In the alert view’s delegate method alertView:clickedButtonAtIndex.

Ah ha! You say, “But didn’t we already use that method to handle the alert view from doMultiButtonAlert?” Yes, we did, but if we’re clever, we can tell the difference between which alert is calling that method and react appropriately.

Because we have access to the view object itself within the alertView:clickedButtonAtIndex method, why don’t we just check the title of the view and, if it is equal to the title of our input alert (Please Enter Your Email Address!), we can set userOutput to the text the user entered in userInput. This is easily accomplished by a simple string comparison using the title property of the alert view object passed to alertView:clickedButtonAtIndex.

Add the following code snippet to the end of the alertView:clickedButtonAtIndex method:

if ([alertView.title
isEqualToString: @"Please Enter Your Email Address!"]) {
userOutput.text=userInput.text;
}

Build and run the application with these changes in place. Now, when the alert view with the text field is dismissed, the delegate method is called and the user output label is properly set to the text the user entered.

Using these techniques, you can expand the capabilities of alert views beyond the simple implementation provided in the base iOS SDK.

Other  
  •  iPhone Application Development : Getting the User’s Attention - Exploring User Alert Methods
  •  iPhone Application Development : Using Advanced Interface Objects and Views - Using Scrolling Views
  •  Working with the Windows Phone 7 Application Life Cycle (part 2) - Managing Application State
  •  Working with the Windows Phone 7 Application Life Cycle (part 1) - Observing Application Life Cycle Events
  •  Mobile Application Security : SymbianOS Security - Development and Security Testing
  •  Mobile Application Security : SymbianOS Security - Introduction to the Platform
  •  Java Mobile Edition Security : Permissions and User Controls
  •  Integrating Applications with the Windows Phone OS : Working with Launchers and Choosers
  •  Introducing Windows Phone 7 Launchers and Choosers
  •  Java Mobile Edition Security : Development and Security Testing (part 3) - Code Security & Application Packaging and Distribution
  •  Java Mobile Edition Security : Development and Security Testing (part 2) - Reverse Engineering and Debugging
  •  Java Mobile Edition Security : Development and Security Testing (part 1) - Configuring a Development Environment and Installing New Platforms & Emulator
  •  Java Mobile Edition Security : Configurations, Profiles, and JSRs
  •  Programming the Mobile Web : Performance Optimization
  •  Programming the Mobile Web : Testing and Debugging (part 3) - Client-Side Debugging
  •  Programming the Mobile Web : Testing and Debugging (part 2) - Server-Side Debugging & Markup Debugging
  •  Programming the Mobile Web : Testing and Debugging (part 1) - Remote Labs
  •  Windows Phone 7 : Working with Controls and Themes - Adding Transition Effects
  •  Windows Phone 7 : Working with Controls and Themes - Understanding Frame and Page Navigation
  •  Windows Phone 7 : Working with Controls and Themes - Panorama and Pivot Controls
  •  
    Top 10
    Programming the Mobile Web : Testing and Debugging (part 2) - Server-Side Debugging & Markup Debugging
    Android Security : ContentProviders
    Combine Multiple Events into a Single Event
    Mixing Windows and Forms
    SQL Server 2008 : T-SQL Stored Procedure Coding Guidelines
    Defensive Database Programming with SQL Server : When Snapshot Isolation Breaks Code
    Windows 7 : Keeping Your Family Safe While Using Your Computer (part 2)
    IIS 7.0 : Performance and Tuning - Network
    Sharepoint 2010 : Business Connectivity Services Deployment Types (part 3) - Configure Indexing & Performing a Search
    The ASP.NET AJAX Control Toolkit (part 3) - The AutoCompleteExtender
    Most View
    Logon Authentication in Windows Vista
    Windows Phone 7 Development : Using Culture Settings with ToString to Display Dates, Times, and Text
    Windows 7 : Using Desktop Gadgets (part 1) - Using the Calendar gadget
    Application Patterns and Tips : Remember the Screen Location & Implement Undo Using Command Objects
    Installing and Maintaining Devices in Vista: The Essentials
    Creating and Managing Views in SQL Server 2008 : Indexed Views
    SQL Server 2008 : Managing Query Performance - Optimizing for Specific Parameter Values
    Remote Administration of Exchange Server 2010 Servers : RDP with Exchange Server 2010 (part 2)
    Programming Excel with VBA and .NET : Variables (part 1) - Names & Declarations
    IIS 7.0 : Implementing Access Control - NTFS ACL-based Authorization & URL Authorization
    Fine-Tuning Windows 7’s Appearance and Performance : Balancing Appearance and Performance
    CSS for Mobile Browsers : Selectors
    WAP and Mobile HTML Security : Application Attacks on Mobile HTML Sites
    Download Web Content via HTTP
    Windows Phone 7 Development : Building a Phone Client to Access a Cloud Service (part 4) - Coding NotepadViewModel
    SQL Server 2008 : Explaining Advanced Query Techniques - Applying Ranking Functions (part 2) - Using RANK, DENSE_RANK and NTILE
    SQL Server 2008 : Explaining XML - XML Indexes
    iPhone 3D Programming : Textures and Image Capture - The PowerVR SDK and Low-Precision Textures
    Windows Phone 7 Development : Working with Controls and Themes - Introducing the Metro Design System
    Exchange Server 2007 : Administrate Transport Settings - Set Transport Rules