A record is the fundamental collection of information in the AddressBook. Records can either be people,
ABPerson; or groups,
ABRecord is itself an abstract class, and is thus never instantiated. Records contain properties and values, which is similar to NSDictionary's use of keys and objects.
An array of all of the people in an address book is obtained by sending a people message to our
ABAddressBook object. Similarly, we can send a groups message to the address book object to get an array containing the groups in the address book.
NSArray *everyone = [book people]; NSArray *everygroup = [book groups]; NSLog( [everyone description] ); NSLog( [everygroup description] );
This will print out the property list representation of the arrays
everyoneElse, which are respectively the top-level groups and people in the address book. The arrays actually contain
ABPerson and ABGroup objects, one for each record. Using the people and groups methods is the quick way into the address book, useful if you want to present the user with a list of available contacts, such as is done in iChat.
A special kind of record in the address book is the record that identifies the current user, or "Me". This record is retrieved from the
ABAddressBook object by sending it a me message. It is also possible to change "me" by invoking the method
ABPerson *me = [book me]; NSLog( [me description] );
New records are created by instantiating either
ABGroup, which is done using alloc and init. When a new record is created, it's given a unique id, which is stored in the
kABUIDProperty defined in ABRecord. Once you have a new record object, you can add it to the address book using the
addRecord:. If you want to remove a record, you may do so by sending a
removeRecord: message to the address book object.
Changes to the address book, including the addition or removal of records, are not made permanent (i.e. not written to file) until the save method of
ABAddressBook is invoked. You can inquire into the existence of unsaved changes using the method
Properties and Values
With the basics of working with records under our belt, it's time to learn how to manipulate the information contained within the record, which is why we're here after all. The first thing one would want to do is determine what's in the record. Property values are accessed using the NSDictionary-inspired method of
ABRecord valueForProperty:. This method takes an
NSString property name, and returns the value for that property. To set the value of a property we use the method
AddressBook defines the following list of
NSString constants that identify the properties that a person may take on:
The list above applies only to
ABPerson type records. Note that the last six properties in the list above are not supported in the Address Book user interface -- so you can use them, but you won't see any evidence of their existence in Address Book. ABGroup type records have only one property:
kABGroupNameProperty. Both people and groups have the following properties, that are part of
The values of properties may be any of the supported property list data types: strings, numbers, dictionaries, dates, and data. Additionally, a property value may be an
ABMultiValue data type, which is how AddressBook stores multiple values for a single property. Multiple values will be discussed at greater length below. In the list of
ABPerson properties, all of the instant message properties are multivalue, as are the email, address, and phone number properties. The remainder are dates or strings.
The example below demonstrates how we can work with properties.
NSArray *everyone = [book people]; ABPerson *someone = [everyone objectAtIndex:0]; NSLog( [someone valueForProperty:kABFirstNameProperty] ); NSLog( [someone valueForProperty:kABLastNamePropertu] ); [someone setValue:@"Pete" forProperty:kABFirstNameProperty]; if ( [book hasUnsavedChanges] ) [book save];
Many property values in the AddressBook are typed as
ABMultiValue, which is an object that stores multiple values for a single property. The idea behind
ABMultiValue is that for many attributes of a person, such as phone numbers, email addresses, and address there exist multiple values. For example, most people have different addresses, phone numbers, and email addresses for their home and work. So rather than create several scattered properties for a work and home properties, AddressBook uses
ABMultiValue which may contain an arbitrary number of values. This is by far a more flexible and cleaner solution.
ABMultiValuee stores the multiple values for a property by index. Associated with each is a unique identifier, a string label, and a value. Generally, the label is some variant of home and work, such as
kABAddressWorkLabel for the address property multi-value. However, it is possible to designate labels for additional values in the multi-value object beyond those for home and work (i.e. A summer vacation home address in addition to home and work). Additionally, while there are home and work labels specific to each multi-value property --
kABXXXXHomeLabel -- AddressBook also defines the generic labels
kABOtherLabel which are equivalent to the property specific labels.
Every multi-value property has what is known as a primary identifier. The primary identifier identifies the sub value of the multi-value property that is most strongly associated with the person. For example, if you interact with a person purely on a professional basis, the primary identifier for that contact in your AddressBook would be for the work value of the contacts various properties. This identifier can be set in a
ABMutableMultiValue using the instance method
setPrimaryIdentifier:. Each multi-value property may have a different primary identifier.
Values are accessed in an
ABMultiValue object by index using the method
valueAtIndex:. If we wanted to access the primary value of the multi-value, we could do so by passing the primary identifier string -- obtained with the primaryIdentifier method -- to the method
indexForIdentifier:. This returned index is then passed to
To demonstrate how multi-value objects are used, let's take a closer look at the
kABAddressBookProperty, a particularly interesting property since it contains NSDictionary objects rather than simple strings. The members of the address dictionary contain all of the pertinent address information such as street number and state. The following list is a list of the keys used to access values in the address dictionaries in the
ABMultiValue object for
kABAddressStreetKey-- The person's street name and number
kABAddressCityKey-- The person's city
kABAddressStateKey-- The person's state
kABAddressZIPKey-- The zip code of the address
kABAddressCountryKey-- The country name of the address
kABAddressCountryCodeKey-- The two character country code. These are standard ISO country codes, and can be found in the header file
Let's take a look at some examples of how we access multi-value properties:
ABMultiValue *addrs = [[book me] valueForProperty:kABAddressProperty]; int count = [addrs count]; // Determining the number of values NSDictionary *addr = [addrs valueAtIndex:0]; NSString *primaryID = [addrs primaryIdentifier]; int idx = [addrs indexForIdentifier:primaryID] NSDictionary *primaryAddr = [addrs valueAtIndex:idx]; NSString *primaryLabel = [addrs labelAtIndex:idx]; NSString *city = [primaryAddr objectForKey:kABAddressCityKey];
Defining New Properties
The AddressBook database is extensible, that is, an application can create additional properties for
ABPerson objects and store information in those properties. Adding new properties will not disturb the way other applications interact with the Address Book -- what they don't know won't hurt them.
To add new properties we first create an
NSDictionary whose keys are the property names, like
kABFirstNameProperty, and the object for that key is the property type. AddressBook supports the following property types:
kABMultiRealProperty: a floating point number
Since property names must be unique, it is best to adopt some naming convention such as is done with preference files: Java-style package naming. Once we have assembled our dictionary of property names and types, we pass it as a parameter to the ABPerson class method
addPropertiesAndTypes:. Here is an example of this:
ABPerson *me = [book me]; NSMutableDictionary *new = [NSMutableDictionary dictionary] [new setObject:@"kABStringProperty" forKey:@"com.myCompany.collegeProperty"]; [new setObject:@"kABDateProperty" forKey:@"com.myCompany.graduationDate]; [me setValue:@"The University of Texas" forProperty::@"com.myCompany.collegeProperty"];
addPropertiesAndTypes: is a class method, it makes the property available for every person in the address book. Because of this, you should be judicious when adding new properties to make sure that it is applicable to a majority of the people in the address book. In other words, don't add address book properties if they only apply to one person in the database. For that,
NSUserDefaults is a better solution.
Adding properties using
addPropertiesAndTypes: has no effect if the property exists already with the specified type. Additionally, once a property has been added, is accessible just as any property. There is no need to add the property before attempting to access the value, or anything like that. You only need to add it the first time.
If you would like to remove a custom property completely, then you can do so using the ABPerson method
removeProperties:. This method takes an NSArray containing all of the property names of the properties you would like removed. It returns the number of properties that were successfully removed.