iOS Reference Library Apple Developer
Search

Working with Address Book Objects

There are four basic kinds of objects that you need to understand in order to interact fully with the Address Book database: address books, records, single-value properties, and multivalue properties. This chapter discusses how data is stored in these objects and describes the functions used to interact with them.

For information on how to interact directly with the Address Book database (for example to add or remove person records), see “Interacting Directly with the Address Book Database.”

Address Books

Address books let you interact with the Address Book database and save changes to it. To use an address book, declare an instance of ABAddressBookRef and set it to the value returned from the function ABAddressBookCreate.

Important: Instances of ABAddressBookRef cannot be used by multiple threads. Each thread must make its own instance by calling ABAddressBookCreate.

After you have created an address book reference, your application can read data from it and save changes to it. To save the changes, use the function ABAddressBookSave; to abandon them, use the function ABAddressBookRevert. To check whether there are unsaved changes, use the function ABAddressBookHasUnsavedChanges.

The following code listing illustrates a common coding pattern for making and saving changes to the address book database:

ABAddressBookRef addressBook;
CFErrorRef error = NULL;
BOOL wantToSaveChanges = YES;
 
addressBook = ABAddressBookCreate();
 
/* ... Work with the address book. ... */
 
if (ABAddressBookHasUnsavedChanges(addressBook)) {
    if (wantToSaveChanges) {
        ABAddressBookSave(addressBook, &error);
    } else {
        ABAddressBookRevert(addressBook);
    }
}
 
if (error != NULL) {/*... Handle error. ...*/}
 
CFRelease(addressBook);

Your application can request to receive a notification when another application (or another thread in the same application) makes changes to the Address Book database. In general, you should register for a notification if you are displaying existing contacts and you want to update the UI to reflect changes to the contacts that may happen while your application is running.

Use the function ABAddressBookRegisterExternalChangeCallback to register a function of the prototype ABExternalChangeCallback. You may register multiple change callbacks by calling ABAddressBookRegisterExternalChangeCallback multiple times with different callbacks or contexts. You can also unregister the function using ABAddressBookUnregisterExternalChangeCallback.

When you receive a change callback, there are two things you can do: If you have no unsaved changes, your code should simply revert your address book to get the most up-to-date data. If you have unsaved changes, you may not want to revert and lose those changes. If this is the case you should save, and the Address Book database will do its best to merge your changes with the external changes. However, you should be prepared to take other appropriate action if the changes cannot be merged and the save fails.

Records

In the Address Book database, information is stored in records. Each record (ABRecordRef) represents a person or group. The function ABRecordGetRecordType returns kABPersonType if the record is a person, and kABGroupType if it is a group. Developers familiar with the Address Book frameworks on Mac OS should note that there are not ABPersonRef or ABGroupRef objects; both person objects and group objects are instances of ABRecordRef.

Important: Record objects cannot be passed across threads safely. Instead, you should pass the corresponding record identifier. See ‚ÄúUsing Record Identifiers‚Äù for more information.

Even though records are usually part of the Address Book database, they can also exist outside of it. This makes them a useful way to store contact information your application is working with.

Within a record, the data is stored as a collection of properties. The properties available for group and person objects are different, but the functions used to access them are the same. The functions ABRecordCopyValue and ABRecordSetValue get and set properties, respectively. Properties can also be removed completely, using the function ABRecordRemoveValue.

Person Records

Person records are made up of both single-value and multivalue properties. Properties that a person can have only one of, such as first name and last name, are stored as single-value properties. Other properties that a person can have more that one of, such as street address and phone number, are multivalue properties. The properties for person records are listed in several sections in “Constants” in ABPerson Reference.

For more information about functions related to directly editing the contents of person records, see “Working with Person Records.”

Group Records

Users may organize their contacts into groups for a variety of reasons. For example, a user may create a group containing coworkers involved in a project, or members of a sports team they play on. Your application can use groups to allow the user to perform an action for several contacts in their address book at the same time.

Group records have only one property, kABGroupNameProperty, which is the name of the group. To get all the people in a group, use the function ABGroupCopyArrayOfAllMembers or ABGroupCopyArrayOfAllMembersWithSortOrdering, which return a CFArrayRef of ABRecordRef objects.

For more information about functions related to directly editing the contents of group records, see “Working with Group Records.”

Properties

There are two basic types of properties, single-value and multivalue. Single-value properties contain data that can only have a single value, such as a person’s name. Multivalue properties contain data that can have multiple values, such as a person’s phone number. Multivalue properties can be either mutable or immutable.

For a list of the properties for person records, see many of the sections within “Constants” in ABPerson Reference. For properties of group records, see “Group Properties” in ABGroup Reference.

Single-Value Properties

The following code listing illustrates getting and setting the value of a single-value property:

ABRecordRef aRecord = ABPersonCreate();
CFErrorRef anError = NULL;
 
ABRecordSetValue(aRecord, kABPersonFirstNameProperty, CFSTR("Katie"), &anError);
ABRecordSetValue(aRecord, kABPersonLastNameProperty, CFSTR("Bell"), &anError);
if (anError != NULL) {/* Handle error here. */}
 
CFStringRef firstName, lastName;
firstName = ABRecordCopyValue(aRecord, kABPersonFirstNameProperty);
lastName  = ABRecordCopyValue(aRecord, kABPersonLastNameProperty);
 
/* ... Do something with firstName and lastName. ... */
 
CFRelease(aRecord);
CFRelease(firstName);
CFRelease(lastName);

Multivalue Properties

Multivalue properties consist of a list of values. Each value has a text label and an identifier associated with it. There can be more than one value with the same label, but the identifier is always unique. There are constants defined for some commonly used text labels—see "Generic Property Labels" in ABPerson Reference.

For example the figure below shows a phone number property. Here, a person has multiple phone numbers, each of which has a text label, such as home or work, and identifier. Note that there are two home phone numbers in this example; they have the same label but different IDs.

Figure 2-1  Multivalue properties

Multivalue Properties

The following functions let you read the contents of multivalue properties:

To keep a reference to a particular value in the multivalue property, store its identifier. You should avoid storing the index, because it will change if values are added or removed. The identifier is guaranteed not to change except across devices.

Mutable Multivalue Properties

Multivalue objects are immutable; to change one you need to make a mutable copy using the function ABMultiValueCreateMutableCopy. You can also create a new mutable multivalue object using the function ABMultiValueCreateMutable.

The following functions let you modify mutable multivalue functions:

Here is a code sample that illustrates getting and setting a multivalue property:

ABMutableMultiValueRef multi =
        ABMultiValueCreateMutable(kABMultiStringPropertyType);
CFErrorRef anError = NULL;
 
// Here, multivalueIdentifier is just for illustration purposes.  Real-world
// code can use this identifier to do additional work with this newly-added
// value.
ABMultiValueIdentifier *multivalueIdentifier;
bool didAdd = ABMultiValueAddValueAndLabel(multi, @"(555) 555-1234",
                      kABPersonPhoneMobileLabel, multivalueIdentifier)
           && ABMultiValueAddValueAndLabel(multi, @"(555) 555-2345",
                      kABPersonPhoneMainLabel, multivalueIdentifier);
if (didAdd != YES) {/* Handle error here. */}
 
ABRecordRef aRecord = ABPersonCreate();
ABRecordSetValue(aRecord, kABPersonPhoneProperty, multi, &anError);
if (anError != NULL) {/* Handle error here. */}
CFRelease(multi);
 
/* ... */
 
CFStringRef phoneNumber, phoneNumberLabel;
multi = ABRecordCopyValue(aRecord, kABPersonPhoneProperty);
 
for (CFIndex i = 0; i < ABMultiValueGetCount(multi); i++) {
    phoneNumberLabel = ABMultiValueCopyLabelAtIndex(multi, i);
    phoneNumber      = ABMultiValueCopyValueAtIndex(multi, i);
 
    /* ... Do something with phoneNumberLabel and phoneNumber. ... */
 
    CFRelease(phoneNumberLabel);
    CFRelease(phoneNumber);
}
 
CFRelease(aRecord);
CFRelease(multi);

Street Addresses

Street addresses are represented as a multivalue of dictionaries. All of the above discussion of multivalues still applies to street addresses. Each of the values has a label, such as home or work (see “Generic Property Labels” in ABPerson Reference), and each value in the multivalue is a street address stored as a dictionary. Within the value, the dictionary contains keys for the different parts of a street address, which are listed in “Address Property” in ABPerson Reference.

Here is a code sample that shows how to set and display a street address:

ABMutableMultiValueRef address =
        ABMultiValueCreateMutable(kABDictionaryPropertyType);
 
// Set up keys and values for the dictionary.
CFStringRef keys[5];
CFStringRef values[5];
keys[0] = kABPersonAddressStreetKey;
keys[1] = kABPersonAddressCityKey;
keys[2] = kABPersonAddressStateKey;
keys[3] = kABPersonAddressZIPKey;
keys[4] = kABPersonAddressCountryKey;
values[0] = CFSTR("1234 Laurel Street");
values[1] = CFSTR("Atlanta");
values[2] = CFSTR("GA");
values[3] = CFSTR("30303");
values[4] = CFSTR("USA");
 
CFDictionaryRef aDict = CFDictionaryCreate(
        kCFAllocatorDefault,
        (void *)keys,
        (void *)values,
        5,
        &kCFCopyStringDictionaryKeyCallBacks,
        &kCFTypeDictionaryValueCallBacks
);
 
// Add the street address to the person record.
ABMultiValueIdentifier identifier;
ABMultiValueAddValueAndLabel(address, aDict, kABHomeLabel, &identifier);
CFRelease(aDict);
 
/* ... Do something with the multivalue, such as adding it to a person record. ...*/
 
CFRelease(address);



Last updated: 2010-07-08

Did this document help you? Yes It's good, but... Not helpful...