Design & Build a 1980s iOS Phone App: Making Phone Calls

Welcome to the sixth installment in our series on how to both design and build a 1980s version of the iOS “Phone” app. In this tutorial I'll be demonstrating how to programmatically launch a phone call from within the iOS SDK and how to respond to user touch events on the keypad.

Final App Preview

This is a snapshot of what we will be building over the course of this series:

1980s App Final Preview

Before You Begin. . .

This is a multi-part series designed to teach intermediate iOS SDK topics. The content will become increasingly complex as the series progresses. If at any point you find yourself lost in following this series, you might need to take a step back and work your way through our Learn Objective-C series or our Beginning iOS SDK Development series.

In the last tutorial in this series, I demonstrated how to skin the phone screen in Xcode 4. In this tutorial, we'll proceed with connecting the interface to our class files and actually code the phone screen logic.

Step 1: Setup the IBOutlets and IBActions

Before we can start coding the phone screen logic, we need to connect the Interface Builder objects added in part four of this series with the XIB "File's Owner" class PhoneViewController. Doing so will allow us to reference the IB objects directly in our PhoneViewController code.

Begin by opening the PhoneView.xib file. Next, select View > Editor > Assistant or just click the "Show the Assistant Editor" button near the top-right of the Xcode toolbar. The assistant window should now be displaying the PhoneViewController.h file, and your screen should look something like this:

Show the assistant in Xcode 4

In the code editor pane, create an IBOutlet UILabel to reference the label that will display the phone number entered by the user:

Next, connect the UILabel to the outlet by CTRL + Clicking on the label in Interface Builder, holding, and dragging to the IBOutlet in the code editor:

Connecting the label IBOutlet

After you've connected the object in IB, go ahead and synthesize this property in the PhoneViewController.m file and be sure to clean up after the memory in the dealloc: and viewDidUnload: methods:

While we're modifying the phoneNumberLabel code, go ahead and remove the dummy phone number value currently set in Interface Builder. This field should be blank until the user begins tapping on the keypad.

Next, create the following three IBAction declarations in PhoneViewController.h:

CTRL + Click on the "1" keypad button to reveal a list of actions available for this button, and then drag from the "Touch up inside" circle to the -(IBAction)numberButtonPressed: method declaration.

Connecting numbers on the keypad with IBActions.

Repeat this process for numbers 2 - 9 and 0, connecting each to the same IBAction method.

Next connect the "Del" button to -(IBAction)deleteButtonPressed: and the "Dial" button to -dialButtonPressed:.

With the necessary connections made, the buttons should now configured to call the appropriate method when tapped. To test this, save your work in Interface Builder and PhoneViewController.h and switch to the PhoneViewController.m file. Add in the following code:

Save the file and run the application. Give a tap on each of the buttons in the keypad. Did you see the appropriate console message logged in the Xcode debug area? If so, you've completed this step successfully!

Step 2: Display Dialed Numbers

With the IBAction and IBOutlet connections made, our next step is to display the keypad numbers in phoneNumberLabel when tapped.

This can be done with just one line of code:

Because the text property of phoneNumberLabel is of type NSString, we are able to simply use the stringByAppendingString: method from the NSString class to concatenate the tapped button's title with the existing value of the phoneNumberLabel text property.

Simple enough. However, wouldn't it be nice if phone number formatting was auto-applied to the label as the user taps along? This is how the official Apple iOS Phone app works, and it is what we will achieve in our application as well.

In order to customize the display, it would be useful to have a temporary NSString object that we can store just the phone digits within. Otherwise, we'd need to constantly strip special characters like "( )" and "-" directly from the text property of phoneNumberLabel, making for kludgy code.

Go back to PhoneViewController.h and add the following property:

Then synthesize this property in the implementation file:

Finally, we want this value to be allocated into memory when the PhoneViewController object is initially unarchived from the XIB file, and we want it to be deallocated from memory when the PhoneViewController object is destroyed.

To allocate the property when the XIB is unarchived, add the following to PhoneViewController.m:

Next, clean up the memory we just added by adding the following line to the dealloc method:

Now back to formatting the values placed in the label.

First, update the numberButtonPressed function to use the newly created phoneNumberString variable instead of the label:

This is a good time to save your files, build, and run the application again. The result should be the same as when you were only using the UILabel, but iterative testing throughout the development cycle is often the best way to find bugs in your own code.

Before moving on to actually formatting the text prior to display in phoneNumberLabel, let's take a few minutes to play with the official Phone app on an iPhone device to determine how our application should behave.

As an aside, a ten-digit U.S. number can be broken down into three consituent parts: the area code, the prefix number, and the line number (for more on what these numbers represent, see here). We'll use these naming conventions in our source code.

If you were watching closely while tapping in numbers on an iPhone, you'll notice that a single dash (i.e. "-") character appears when the user enters the fourth digit, and that this dash is replaced with area code parentheses and a second dash character when the user enters the eighth digit. This makes perfect sense as it successfully accounts for both seven digit local calls (i.e. 555-5555) and ten digit long-distance calls (i.e. (555) 555-5555).

To replicate this behavior, we'll need to alter the formatting of the phone number label when the user reaches a number between four and ten digits long or when the user reaches a number between seven digits and ten digits long. Per the functionality of the iPhone Phone app, anything entered that is either longer or shorter than those values will simply be displayed as a single, solid line of digits.

Let's begin by formatting numbers entered between four and seven digits long:

In the code above, we first use the length method of NSString, which returns a count of the total numbers in the receiving string, to craft a conditional that will only be executed when the phone number is between four and seven digits long.

Next we create an NSRange to hold the prefix position entered, that is, placeholder characters 1 - 3 in the phoneNumberString. The next line is a temporary variable to actually hold the number prefix data. Then we use the substringFromIndex: method to take the portion of the phone string from the index number supplied to the end of the string. Finally, we use the stringWithFormat: method to craft our custom display string and assign it to the text property of the UILabel.

We need to take similar steps for digits entered in the eight to ten range:

The same basic pattern is used again above. The phoneNumber string is split into several substrings using the substringWithRange: and substringFromIndex: methods of NSString before they are joined together again in the desired format by stringWithFormat:.

Of course, if the number of digits entered by the user is either greater than ten or less than four, we want to just display them without any special formatting:

The code above should correctly format the digits pressed by the user as they are entered on the keypad. Save, build, and run your application once again now.

If all is well so far, congrats! Next we're going to make the code a bit more modular by placing the display logic we just wrote into a function named -(void)displayPhoneNumber. Why? Because this display logic will be needed both when adding new digits to the display and when deleting them, so it's best not to repeat ourselves.

In the end, the displayPhoneNumber and numberButtonPressed: methods should look like this:

Of course, you'll also need to add a method declaration in PhoneViewController.h as well:

With these forward thinking steps completed, get ready to delete some digits!

Step 3: Activate the Delete Button

Removing a button from the phoneNumberString variable is easy enough:

We just need to calculate the current length of the string and subtract one character from the end. This is done above with the substringToIndex: method, which essentially does the reverse: it returns all the characters up to a certain point, in this case, one minus the length of the string.

This works well enough, but what would happen with this code snippet if the user pressed delete button before entering a digit? We need to account for that edge case, and we also need to call our displayPhoneNumber method again to properly format the output. When these two tasks are complete, the code should look like this:

You know the drill: save, build, and run the app again to see this step in action.

Step 4: Making Phone Calls

Our last step is likely also the most anticipated: launching a phone call from within our app! Doing so will only take three lines of code:

First, we create a special URL string that is prefixed with "tel:". This indicates to the iOS SDK that we want to call the Phone application and pass in the proceeding variable, in this case the value stored in phoneNumberString.

The next line actually creates an NSURL object that we will use to launch the call, and the final line sends a message to the UIApplication object to actually launch the call. The details of UIApplication are beyond the scope of this tutorial, but it is often used when you want to open applications outside of your own, including Mobile Safari and the Maps app.

If everything went well, you should now be able to enter and delete numbers on the keypad as well as launch a phone call from within our app!

In case you didn't notice, there is one small but very important detail missing: tapping on an individual digit is a silent event, and what kind of an 80s phone would be complete without sound effects? This issue will be addressed in a future tutorial.

Conclusion

Over the course of this tutorial, I've shown you how to respond to touch events on the keypad and programmatically initiate a phone call with the iOS SDK. If you have any questions, feel free to leave them in the comment section below!

Tags:

Comments

Related Articles