18. Connecting to the Address Book

In addition to standard user interface controls and media components that you’d see on any computer, the iPhone SDK provides a number of tightly focused developer solutions specific to iPhone and iPod touch delivery. The most useful of these include Address Book access, allowing you to programmatically access and manage the contacts database. This chapter introduces the Address Book and demonstrates how to use its frameworks in your applications. You read about accessing information on a contact-by-contact basis, how to modify and update contact information, and how to use predicates to find just the contact you’re interested in. This chapter also covers the GUI classes that provide interactive solutions for picking, viewing, and modifying contacts. By the time you’ve read through this chapter, you’ll have discovered the address book from the bottom up.

Recipe: Working with the Address Book

The iPhone SDK provides not one but two address book frameworks. These are AddressBook.framework and AddressBookUI.framework. As their names suggest, they occupy distinct niches in the iPhone SDK. AddressBook provides low-level C-based structures and routines for accessing contact information from the iPhone’s onboard SQLite databases. AddressBookUI offers high-level Objective-C based UIViewController browser objects to present to users. Both frameworks are small. They provide just a few classes and data types.

On the iPhone, contact data resides in the home Library folder. On the Macintosh-based iPhone simulator, you can freely access these files in ~/Library/Application Support/iPhone Simulator/User/Library/AddressBook. The two files, AddressBook.sqlitedb and AddressBookImages.sqlitedb use standard SQLite to store contact information and, in the latter file, optional contact images. On the iPhone, the same files live in /var/mobile/Library/AddressBook, that is, out of the application sandbox. You must use the two Address Book frameworks to query or modify the user’s contact information rather than accessing these files directly.

Address Book UI

The AddressBookUI framework provides several precooked view controllers that interact with the onboard contacts database. These interfaces include a general people picker, a contact viewer, and a contact editor. You set a delegate and then push these controllers onto your navigation stack or display them modally, as shown in the recipes in this chapter.

Like the image picker and video camera controllers you saw in Chapter 7, “Working with Images,” and Chapter 15, “Audio, Video, and MediaKit,” the AddressBookUI controllers are not very flexible. Apple intends you to use them as provided, with little or no customization from the developer. What’s more, they require a certain degree of low-level programming prowess. As you see in this chapter, these classes interact with the underlying Address Book in circuitous ways.

Address Book

In the C-based AddressBook framework, the ABRecordRef type provides a core contact structure. This record stores all information for each contact, including name, e-mail, phone numbers, and so forth. Every record corresponds to a complete address book contact. Query the address book for the number of objects currently stored in its database. Despite the name, the ABAdressbookCreate() function does not create a new address book; it creates a reference to the system address book.

image

Recover individual records by calling the ABAddressBookCopyArrayOfAllPeople() function. The following method retrieves those records as an array and then adds each record into an ABContact object. ABContact is a custom Objective-C wrapper developed for this book. Objective-C wrappers provide easy integration between the C-based address book calls and normal Cocoa Touch development and memory management. The full source for this, and a couple of other wrapper classes, can be found in the sample code for this chapter.

image

The ABContact class hides an internal ABRecordRef, the CF type that corresponds to each contact record. The remaining portion of the wrapper involves nothing more than generating properties and methods that allow you to reach into the ABRecordRef to set and access its subrecords.

image

Nearly all ABRecordRef functions use the ABPerson prefix. This prefix corresponds to the ABPerson class that is available on the Macintosh but not on the iPhone. So while the function calls are ABPerson-centric, all the data affected by these calls are actually ABRecordRef instances. The reason for this becomes clearer when you notice that the same ABRecordRef structure is used in the AddressBook framework to represent both people (individual contacts, whether people or businesses) and groups (collections of contacts, such as work colleagues and personal friends). The SDK provides ABGroup functions as well as ABPerson ones. You read about groups later in this section.

Retrieving and Setting ABRecord Strings

Each ABRecord stores a number of simple string values that represent, along with other items, a person’s name, title, job, and organization. Retrieve these items by copying field values from the record. The following method uses a property constant (ABPropertyID) that identifies the requested field in the record. The method copies this value, casts it to a string, and returns that content.

image

The 13 string-based fields you can recover in this fashion are as follows. These identifiers are defined as constant integers in the ABPerson.h header file. They identify fields in an ABRecordRef that store a single string for each property.

kABPersonFirstNameProperty

kABPersonLastNameProperty

kABPersonMiddleNameProperty

kABPersonPrefixProperty

kABPersonSuffixProperty

kABPersonNicknameProperty

kABPersonFirstNamePhoneticProperty

kABPersonLastNamePhoneticProperty

kABPersonMiddleNamePhoneticProperty

kABPersonOrganizationProperty

kABPersonJobTitleProperty

kABPersonDepartmentProperty

kABPersonNoteProperty

Setting string-based properties proves to be just as simple as retrieving them. Cast the string you want to set to a CFStringRef. Use ABRecordSetValue() to store the data back into the record. Take note that these calls do not update the address book. They only change the data within the record. If you want to store a user’s contact information, you have to write that information back to the address book. A solution for doing so follows later in this section.

image

Simple Date Properties

In addition to the string properties you just saw, the address book stores three key dates: an optional birthday, the date the record was created, and the date the record was last modified. These items use the following property constants.

kABPersonBirthdayProperty

kABPersonCreationDateProperty

kABPersonModificationDateProperty

Access these items exactly as you would with strings but cast to and from NSDate instances instead of NSString instances. Although you can, theoretically, modify the latter two properties, you’re best allowing the address book to handle them.

image

Getting and Setting Multivalue Record Properties

Each person may have multiple e-mail addresses, phone numbers, and important dates (beyond the birthday singleton) associated with his or her contact. ABPerson uses a multivalue structure to store lists of these items. Each multivalue item is basically an array. You can recover each array from the record via its property identifier. Instead of returning a string, the record returns a CFArrayRef.

The multivalue property identifiers you may work with are as follows:

kABPersonEmailProperty

kABPersonPhoneProperty

kABPersonURLProperty

kABPersonDateProperty

kABPersonAddressProperty

kABPersonInstantMessageProperty

The first three of these items (e-mail, phone, and URL) store multistrings—that is, arrays of strings. Their associated type is the kABMultiStringPropertyType. Each multivalue type plays an important role in storing data back to the record. The type is used to allocate memory and determine the size for each field within the record.

The next item, the date property, stores an array of dates using kABMultiDateTimePropertyType. Both the address and instant message properties consist of arrays of dictionaries and use kABMultiDictionaryPropertyType.

Note

“Related names” represents another multistring property but one that does not actually get used on the iPhone Contacts application at this time. It uses the kABPersonRelatedNamesProperty constant and stores names and their relationships, for example, Mary Ball Washington might be stored in George Washington’s contact using the kABPersonMotherLabel. See ABPerson.h for a full list of relation constants.

It’s straightforward to retrieve an array of values for any of these properties. Just copy the property out of the record (using ABRecordCopyValue()) and then break it down into its component array. The address book provides a function that copies the array from the property into a standard CFArrayRef.

image

Although you might think you’ve retrieved all the information with those two calls, you have not. Value retrieval alone is not sufficient for working with multivalued items. Each element stored in a multivalue array uses a label as well as a value. Figure 18-1 shows part of an address book contact page. Grouped items use labels to differentiate the role for each e-mail, phone number, and so forth. This contact has three phone numbers and three e-mail address, each of which displays a label indicating the value’s role.

Figure 18-1 Multivalue items consist of both a label (e.g., main, Google, and mobile for these phone numbers, or home, work, and Google for these e-mail addresses) and a value.

image

You must copy the labels from the property as well as the values to retrieve all the information stored for each multivalue property. The following method copies each label by its index and adds it to a labels array. Together, the labels and the values comprise a complete multivalue collection.

image

Saving into multivalue objects works the same way but in reverse. To store multivalued items into a record, you must transform your Cocoa Touch objects into a form the record can work with. The following method expects an array of dictionaries. Each dictionary must contain two keys: value and label. The objects for these keys correspond to the value and label retrieved from the original multivalued property. This code iterates through that array of dictionaries and adds each value and label to the mutable multivalue object.

image

Notice how this method creates the multivalue object using an ABPropertyType supplied as the method parameter. This is where the various kinds of multistring types come into play.

For example, you can populate an e-mail property with strings and labels using kABMultiStringPropertyType. This method calls the one that creates a multivalue object, providing both value-label dictionaries and the multiproperty type to use. Once that multivalue item is created, it is passed to another method to be set.

image

Assigning a multivalue object to a record is simple. Use the standard ABRecordSetValue() call. The following method performs the assignment of a multivalued object to a property within a record. There is essentially no difference between this call and the calls that set a single date or string property. All the work is done in creating the multivalue item in the first place.

image

Addresses and Instant Message Properties

Both address and instant message (SMS) properties use dictionaries rather than strings or dates. This adds an extra step to the creation of a multivalue array. You must populate a set of dictionaries and then add them to an array along with their labels. Figure 18-2 illustrates this additional layer. As this figure shows, e-mail multivalue items consist of an array of label-value pairs, where each value is a single string. In contrast, addresses use a separate dictionary, which is bundled into the value item.

Figure 18-2 Unlike multivalue e-mail, which stores a single string for each value, multivalue addresses contain an entire address dictionary.

image

Here’s an example that demonstrates the steps involved in creating a two-address multivalue item. This code builds the dictionaries and then adds them, along with their labels, to a base array. The array created by this code corresponds to the multivalue address object shown on the right side of Figure 18-2.

image

This code relies on convenience methods to create both the address dictionaries and the value/label dictionaries used for the multivalue array. The following methods produce the label/value dictionaries, and the address and SMS dictionaries. Notice how the keys for the address and SMS dictionaries are predefined, using address book key constants.

image

image

Working with Address Book Images

Each record in the address book may be associated with an optional image. You can copy image data to and from each record. The ABPersonHasImageData() function indicates whether data is available for a given record. Use this to test whether you can retrieve image data.

Image data is stored as CFData, which is toll-free bridged with NSData. As the UIImage class fully supports converting images into data and creating images from data, you just need to cast that data as needed. Use the UIImagePNGRepresentation() function to transform a UIImage instance into an NSData representation. Use imageWithData: to create a new image from NSData.

image

Creating, Adding, and Deleting Records

The ABPersonCreate() function returns a new ABRecordRef instance. This record exists outside the address book and represents a freestanding data structure. To date, all the methods you’ve seen in this chapter have modified individual records, but none so far has actually saved a record to the address book. Keep that in mind as you look at this convenience method that returns a newly initialized contact.

image

To write new information to the address book takes two steps. You must add the record and then save the address book. New iPhone developers often forget the second step, leading to an address book that appears to resist changes. This method adds a new contact to the address book, first by adding the record and then by saving the changes.

image

You cannot overwrite new contact information to a contact that already exists in the address book. If you create a new “George Washington” record and attempt to save it to an address book that already has a “George Washington” record, you’ll fail. That’s because the new record does not have the same record identifier as the original. The mismatch between the two records causes the error. Here is how you query a record for its unique identifier.

- (ABRecordID) recordID {return ABRecordGetRecordID(record);}

You can update contact information only by reading out the existing record, modifying it, and saving it (this approach is used in Recipe 18-7), or by removing the record and then adding back a new version.

Removing a record from the address book requires a save step, just like adding a record. Once removed, the record still exists as an object, but it no longer is stored in the address book database. Here’s how you can remove a record from the address book.

image

Searching for Contacts

The default address book framework allows you to perform a prefix search across records. This function returns an array of records whose composite names (typically first name appended by last name, but localizable to countries where that pattern is reversed) match the supplied string.

NSArray *array = (NSArray *)ABAddressBookCopyPeopleWithName(
          addressBook, CFSTR("Eri"));

Note

Address Book routines are written using C-based Core Foundation libraries. Many classes live in both the Cocoa Touch Foundation and Core Foundation worlds. For example, an NSArray* pointer corresponds to Core Foundation CFArrayRef. These classes are “toll free bridged.” They provide identical structure and functionality, and you can cast one to the other without penalty. The snippet shown above casts the array reference returned by the Core Foundation ABAddressBookCopyPeopleWithName() into an NSArray pointer for easier Objective-C wrapping.

It’s far easier to combine a set of properties, like those provided in the custom ABContact class, with NSPredicate instances. The following code matches a string against a contact’s first name, middle name, last name, and nickname. The predicate uses property names to define how it matches or rejects contacts. It does this using a case and diacritical insensitive match ([cd]) that compares against all points within each string (contains), not just the start (begins with).

image

Note

Apple’s Predicate Programming Guide offers a comprehensive introduction to predicate basics. It demonstrates how to create predicates and use them in your application.

Working with Groups

Groups allow you to collect contacts into related sets such as work, home, and other natural groupings. Each group is nothing more than another ABRecord but with a few special properties. Groups don’t store names, addresses, and phone numbers. Instead, they store a reference to other contact records.

Are you unfamiliar with groups on the iPhone? That’s because Apple’s iPhone Contact application doesn’t provide a way to create them. The only way to add groups of contacts to your iPhone is via the SDK or by synchronizing an address book from your Macintosh.

You can count the number of groups in the current address book by retrieving the group records, as shown in this method. There’s no direct way to query the number of groups as there is with the number of person contacts. The following methods are part of an ABGroup wrapper class that provides an Objective-C wrapper for address book groups like ABContact wraps address book contacts.

image

Create groups using the ABGroupCreate() function. This function returns an ABRecordRef in the same way that ABPersonCreate() does. The difference lies in the record type. For groups, this property is set to kABGroupType instead of kABPersonType.

image

Add and remove members of a group by calling ABGroupAddMember() and ABGroupRemoveMember(). These calls affect records only and are not stored until you save the address book.

image

Each member of a group is a person, or using this chapter’s ABContact terminology, a contact. This method scans through a group’s members and returns an array of ABContact instances, each initialized with the ABRecordRef for a group member.

image

Every group has a name. It is the primary group property that you can set and retrieve. It uses the kABGroupNamePropert identifier, and it otherwise works just like the contacts properties.

image

ABContact, ABGroup, and ABContactsHelper

The sample code that accompanies this section includes source for three wrapper classes. The snippets shown throughout this discussion highlight the techniques used in these classes. Due to the length and overall redundancy of the classes, a single recipe listing (normally Recipe 18-1) has been omitted from this section. The examples you’ve already seen together comprise this section’s “recipe.” The sample code joins these techniques together into a group of Address Book wrappers. So Recipe 18-1 can be found in the sample code for this chapter.

The custom ABContact class is somewhat based on the Mac-only ABPerson class. It provides a more Cocoa Touch interface with built-in Objective-C 2.0 properties than the C-style property queries that Apple’s ABPerson uses. All the contact-specific methods you’ve seen to date in this section derive from this class.

A second class called ABGroup wraps all the group functionality for ABRecordRef instances. It offers Objective-C access to group creation and management. Use this class to build new classes, and add and remove members.

The final class, ABContactsHelper provides address book-specific methods. Use this class to search through the address book, retrieve arrays of records, and so forth. Although I have included a few basic searches across names and phone numbers, you can easily expand this class, which is hosted at http://github.com/erica, for more complex queries.

Recipe: Searching the Address Book

Predicate-based searches are both fast and effective. Recipe 18-2 shows predicate-based queries in action. It presents a search table (like the one introduced in Recipe 11-16) that displays a scrolling table of contacts. This table responds to user search bar queries with live updates.

Recipe 18-2 Selecting and Displaying Contacts with Search

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

Because search tables have two data sources, this recipe uses two arrays. A contacts array stores the entire address book contacts list. A second, filtered array is built each time the user updates the search bar, using the contactsMatchingName: method you just read about in the preceding section.

When a user taps a row, this recipe displays an ABPersonViewController instance. This class offers a view that displays the details for a given record, similar to Figure 18-1. To use this view controller, you allocate and initialize it and set its displayedPerson property. As you’d expect, this property stores an ABRecordRef.

Person view controllers offer a limited delegate. By setting the personViewDelegate property, you can subscribe to the personViewController:shouldPerformDefaultActionForPerson: method. This method triggers when users select certain items in the view, including phone numbers, e-mail addresses, URLs, and addresses. Return YES to perform the default action (dialing, e-mailing, etc.) or NO to skip. Recipe 18-2 uses this callback to display the value for the selected item in the debug console. Although you can interact with other display elements like the contact note and ringtone, these items do not produce callbacks.

To extend this recipe to allow editing, set the person view controller’s allowsEditing property to YES. This provides the edit button that appears at the top right of the display. When tapped, the edit button triggers the same editing features in the person view that you normally see in the Contacts application.

Recipe: Accessing Image Data

Recipe 18-3 expands on Recipe 18-2 by adding contact image thumbnails to each table cell. It does this by creating a new 45-by-45 pixel image. When image data is available, that image is rendered onto the thumbnail. When it is not, the thumbnail is left blank. Upon being drawn, the image is assigned to the cell’s imageView. Please note that the imageView property was introduced in the 3.0 SDK. For deployment to pre-3.0 firmware, you may use the cell’s image property, which is now deprecated.

Recipe 18-3 Displaying Address Book Images in Table Cells

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

Figure 18-3 shows the interface for this recipe. In this screenshot, a search is in progress (matching against the letter “e”). The records that match the search each display their image thumbnail.

Figure 18-3 You can easily retrieve and display the image data associated with address book contacts.

image

Notice how simple it is to create and use thumbnails in this recipe. It takes just a few lines of code to build a new image context, draw into it (for contacts with images), and save it out to a UIImage instance.

Recipe: Picking People

The AddressBookUI framework offers a handy people picker controller. Browsing your entire Contacts list is just as easily accomplished as displaying an individual contact screen. Use the ABPeoplePickerNavigationController class to present an interactive browser, as shown in Figure 18-4.

Figure 18-4 The iPhone people picker navigation control enables users to search through the contacts database and select a person or organization.

image

Allocate and display the controller before presenting it modally. Make sure to set the peoplePickerDelegate property, which allows you to catch user interactions with the view.

image

When you declare the ABPeoplePickerNavigationControllerDelegate protocol, your class must implement the following three methods. These methods respond to users when they tap a contact, or any of a contact’s properties, or when the user taps Cancel:

peoplePickerNavigationController:shouldContinueAfterSelectingPerson:—When users tap a contact, you have two choices. You can accept the person as the final selection and dismiss the modal view controller (as is done here in Recipe 18-4), or you can navigate to the individual display. To pick just the person, this method returns NO. To continue to the individual screen, return YES. The second argument contains the selected person, in case you want to stop after selecting any ABPerson record.

Recipe 18-4 Picking People

image

peoplePickerNavigationController:shouldContinueAfterSelectingPerson:property:identifier:—This method does not get called until the user has progressed to an individual contact display screen. Then, it’s up to you whether to return control to your program (return NO) or to continue (return YES). You can determine which property has been tapped and to recover its value using the code from Recipe 18-2. Although this method should be optional, it is not at the time of writing this book.

peoplePickerNavigationControllerDidCancel:—When a user taps Cancel, you still want a chance to dismiss the modal view. This method catches the cancel event, allowing you to use it to perform the dismissal.

Recipe 18-4 presents the simplest possible people picking example. It presents the picker and waits for a user to select a contact. When the user does so, it dismisses the picker and changes the view controller title (in the navigation bar) to show the composite name of the selected person. Returning NO from the primary callback means the property callback will never be called. You must still include it in your code as all three methods are required.

Recipe: Limiting Contact Picker Properties

When you need users to pick a certain kind of property, such as an e-mail address, you won’t want to present users with a person’s street address or fax number. Limit the picker’s displayed properties to show just those items you want the users to select from. Figure 18-5’s picker has been limited to e-mail selection.

Figure 18-5 The people picker’s displayed properties allows you to choose which properties to present to users, in this case e-mail only.

image

To make this happen, choose the displayed properties by submitting an array of property types to the controller. Set the picker’s displayedProperties property. Recipe 18-5 offers two picking options, one for e-mail, the other for phone numbers. Although these examples use a single property for the properties array, you can choose to display any number of properties.

Recipe 18-5 Choosing Display Properties

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

Recipe: Adding New Contacts

Allow your users to create new contacts with the ABNewPersonViewController class. This view controller offers an editing screen that simplifies the interactive creation of a new address book entry. After allocating and initializing the view controller, start by creating a new contact and assigning it to the displayedPerson property. If you want, you can prefill the contact’s record with properties first. Recipe 18-7, which follows this one, uses prefilling to modify already-existing contacts.

Next, assign the newPersonViewDelegate and declare the ABNewPersonViewControllerDelegate protocol. Delegates receive one callback, newPersonViewController:didCompleteWithNewPerson:. This callback is sent for both selection and cancel events. Check the person parameter to determine which case applies, as shown in Recipe 18-6.

Recipe 18-6 Using the New Person View Controller

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

If the user taps Done after editing the new contact, save the contact data to the address book. If you’re doing this manually rather than using the ABContactsHelper helper class, make sure you both add the record and save the address book.

When a contact already exists with the same credentials, you need to handle the situation in some fashion. This recipe removes the existing contact to replace it with the new one, but you can also throw up an alert and ask the user how to proceed. The user might choose to keep the original or the replacement, or if you want, you can try to merge the two records somehow.

Recipe: Modifying Existing Contacts

Recipe 18-7 uses the ABNewPersonViewController class’s ability to prefill a form to modify existing contacts. The modify method starts by presenting a people picker controller. Once a user selects a contact, the application responds by using that contact information to populate the new person controller, which is then pushed onto the navigation stack.

Recipe 18-7 Selecting and Modifying an Address Book Contact

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

As with Recipe 18-6, the code differentiates between cancel and done. This recipe, however, does not try to replace an existing contact. Instead, it simply adds the contact back into place. The contact’s record ID is established by the people picker, and that same record ID allows the new changes to overwrite the old.

Recipe: The ABUnknownPersonViewController

What happens when you have some information like an e-mail address or a phone number, but you don’t have a contact to associate with it yet? The ABUnknownPersonViewController allows you to add that information to a new or existing contact. This class exists to associate known properties with unknown contacts. It works like this.

You allocate and initialize the view controller and then create and prefill a record. Recipe 18-8 defines a record with a single e-mail address. You can add more items if you want, and each will be displayed in the view controller. Figure 18-6 (left) shows this recipe’s controller with its single e-mail. Assign the prefilled record to the displayedPerson property.

Recipe 18-8 Adding Existing Properties to Contacts

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

Figure 18-6 (Left) The Unknown Person Controller allows you to display properties and add them to a new or existing contact. (Middle) The properties you set prefill the new contact form when the user taps Create New Contact. (Right) When you disable the address book features and enable actions, you create a sheet that offers one-tap access to phone numbers, e-mail addresses, URLs, and so forth.

image

The Create New Contact and Add to Existing Contact buttons are controlled by the allowsAddingToAddressBook property. When a user taps on the new contact button, a form appears (see Figure 18-6, middle) that is prefilled with the properties from that record. If you disable this adding property, the buttons do not appear (see Figure 18-6, right). When you set the allowsAction property to YES, users can still tap on these elements to connect to an e-mail address, to phone numbers, and so forth. This provides a handy way to present a list of interactive contact information and URLs with an already-defined view controller.

The alternateName and message properties provide the text that fills the name and organization fields in Figure 18-6 (left). Although you can populate these fields with data via the record, the alternate options do not transfer to contacts. Therefore they provide a nice way to prompt the user without side effects.

Set the unknownPersonViewDelegate property and declare the ABUnknownPersonViewControllerDelegate protocol to receive the unknownPersonViewController:didResolveToPerson: method. Called when the user taps Done, this method allows you to recover the record that the data was saved to. It also provides a place where you can pop the view controller and release it, knowing that the user has finished interaction with the dialog.

One More Thing: Adding Random Contact Art

The Monster ID project consists of a collection of body part art that can be compiled together to form random pictures. It was developed by Andreas Gohr, and was inspired by a Web post by Don Park and the combinatoric critters. Built up by adding predrawn arms, legs, a body, and so forth, the resulting composite image produces a full creature.

The randomImage method in Recipe 18-9 builds a monster image from its components. This art can be assigned directly to an address book contact or can be used as the seed for a new contact using the unknown person controller. Either way, you can use an ABContact instance and assign an image using its image property. If you’re not using the controller, don’t forget to save the address book after updating a record’s image.

Recipe 18-9 Combining Random Art with the Unknown Person Controller

image

image

Get This Recipe’s Code

To get the code used for this recipe, go to http://github.com/erica/iphone-3.0-cookbook-, or if you’ve downloaded the disk image containing all of the sample code from the book, go to the folder for Chapter 18 and open the project for this recipe.

Recipe 18-9 uses the unknown person controller approach. When the user taps an action button, it requests a Monster ID image and presents the controller, which is shown in Figure 18-7. The image appears in the Info page, and the standard create/add buttons allow users to add the generated art to a new or existing contact. Users can tap Back to return without adding the image. A new monster generates each time the sheet appears.

Figure 18-7 You can add images to contacts with the unknown person controller as well as e-mail addresses, phone numbers, and other text-based data.

image

Summary

This chapter introduced Address Book core functionality for both the AddressBook and AddressBookUI frameworks. Here are a few parting thoughts about the frameworks you just encountered:

• Although useful, the low-level Address Book functions can prove frustrating to work with directly. The various helper classes that accompany this chapter may help make your life a little easier.

• Accessing and modifying an address book image works like any other field. Supply image data instead of strings, dates, or multivalue arrays. Don’t hesitate to use image data in your contacts applications.

• The view controllers provided by the AddressBookUI framework work seamlessly with the underlying AddressBook routines. There’s no need to roll your own GUIs for most common address book interaction tasks.

• The unknown person controller provides a really great way to store specific information (such as a company’s e-mail address, an important Web site, etc.) into a contact while allowing user discretion for where (or whether) to place that information.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.116.14.118