address book

A First Look at Contacts Framework in iOS 9

As every iOS release, the version 9, which is officially here for just a few weeks, presents new features and improvements to existing technologies for both users and developers. As we’ve all witnessed, there’s a number of new stuff that has been first-introduced in this version, but there are changes and updates to existing frameworks and libraries as well. Additionally, and that’s always surprising, there are cases where old APIs are left aside and become deprecated, making room for new ones that have been implemented from ground up to fill in the gap instead. The greatest example in iOS 9 is the all brand new Contacts framework, which is here to replace the old AddressBook framework in a fashion modern, simple and a lot more straightforward.

Every developer that has dealt with the AddressBook API in the past can definitely say that it wasn’t the most easy part of the iOS SDK to work with. In general, the AddressBook was difficult to understand and manage, and that fact was even more intense in new developers. All that belongs to history, as the new Contacts framework is way simpler to understand and use; contacts can be fetched, created or updated in no time at all, the contacts-related development time can be dramatically decreased, changes and modification can be done really fast.

In the next few paragraphs we’ll highlight the most important aspects of the Contacts framework. I won’t go into much details, as you can find them all in the official Apple documentation, and the WWDC 2015 session 223 video.

So, first of all, I’ll begin by something crucial, and that is the user privacy. Users are always being asked if they grant access to their contacts data through an application. If they do so, then the app can freely interact with the user’s contacts database. If, on the other hand, users prohibit access to the contacts data, then this decision must be respected by the app and not interact with it at all. In a while we’ll talk more specifically about it, and we’ll see how all possible situations are handled programmatically. Furthermore, keep in mind that the user is always eligible to change the authorization state of the app through the device Settings, so you should always check if your app has the required permissions to access the contacts data or not right before you perform any related task.

The main source of contacts data is always the database existing in a device. However, the Contacts framework does not lookup just there when an app asks for contact data. In fact, it searches for contacts in other sources too, like your iCloud account (if you’re connected to it of course), and returns back to the app unified contacts that originate from various sources. This is quite useful, as you don’t have to initiate separate searches for contacts residing in databases other than the device’s. You have them all at once, and you manage them as you like.

The Contacts framework has a number of classes that serve specific purposes. All of them have their importance, but the one that is used the most, is called CNContactStore. This one represents the contacts database programmatically, and provides various methods for performing tasks like fetching, saving or updating records, authorization check and authorization request, and many more. A single contact is represented by the CNContact class, but keep in mind that the properties of that class are immutable. If you want to create a new contact or update an existing one, you must use the CNMutableContact one. Note that when dealing with the Contacts framework, and especially when fetching contacts, you should always perform those tasks in background threads. If a contact fetching task takes too much time and is working in the main thread, then your app may become unresponsive, and eventually end up to a bad user experience.

Rarely all of the contact properties are really needed when importing contacts into an app. Fetching all data for all contacts existing in all sources that the Contacts framework searches into, can be proved a resource-eating process, so you should avoid doing that unless you’re sure that you’re going to use all of the data pieces, up to the last one. Thankfully the Contacts framework provides ways for fetching partial results, meaning just a subset of properties regarding a contact. For example, you could ask only for the first and last name, the home email address, and the home phone number, and save that way a lot of resources by leaving aside all that data you don’t really need.

Besides all the programmatic access that the Contacts framework provides, it also supports some default UI that can be incorporated in applications and have that way direct and visual access to contacts. The provided UI is pretty much same to the Contacts app, so that means that there’s a contact picker view controller along with the details card that can be used to pick contacts and properties (it can be customized up to a level), and a contacts view controller to display the contact details and perform certain actions (for example, to make a call).

All of the above are aspects that we’ll see in details in the following parts of this tutorial. Once again, visit the official documentation for additional information on what I presented or what I’ll present from now on. Let’s see now what the demo application is going to be, and then let’s get started dealing with the Contacts framework classes. You’ll find out that it’s easy and funny messing with this new framework.

Continue reading my tutorial on Appcoda

How To Import Contacts Using Address Book Framework

One of the most well-known and most used feature of iPhone devices to all users, developers or not, is the Address Book. For those who use a lot the device as a phone (rather than a mobile mini computer), all important and vital information they need exist in their contacts. Till today, many applications have been developed, and even more can be built that make use the device’s address book data.

Apple makes developers’ life easy, as it provides frameworks that allow to access the address book and deal with its records. Knowing how to work with address book and how to perform some basic tasks (at least), is a knowledge necessary to all developers, as either sooner or later they’ll come in need of integrating address book info into their applications.

Before we proceed to take a tour on the most important aspects of the address book framework through a demo application, it would be a nice idea to make an introductory discussion first that will make easier to everyone to comprehend what comes next in this tutorial. So, keep reading and surely you’ll find some pretty interesting stuff as food for thinking and study.

Read the full tutorial on Appcoda

How to import contacts from the Address Book – Part 2

Welcome to the second part of this tutorial! At the first part we talked about a couple of things on how to import contacts from the device’s Address Book and we developed a demo app to see everything in action. What we really did, was to let us tap on a contact’s name, return back to our app and then select specific pieces of information regarding the selected contact, which we displayed on a table view.

In this part what we’ll do is going just one step further. We will change a little bit our app and when the user taps on a contact’s name a new window will be shown to display specific piece of information. That information will be the e-mail addresses of the contact only. Further more, from the total of the e-mail addresses we’ll pick just one by tapping (clicking on the Simulator) on it and that’s going to be the e-mail address that we’ll display into our table view.

I should also mention that I’m going to base this part of the tutorial on the previous one. That means that I’m going to get the app we implemented into the first part of this tutorial and make some modifications. That also means that, even if you don’t want to read the previous part, at least you’ll have to get the code and implement the demo app if you’d like to follow up this tutorial. So, I keep going having in mind that you have read or implemented the previous app of our example.

Let’s get started.


Step 1

In the previously developed demo app, we created an IBAction named addContact. This action method allows us to open the Address Book and get the contacts from it. What we’re going to do now, is to add one more command inside the IBAction. This new command will define the specific piece of information of the contact we want to display. So, go into the addContact IBAction and add the following line just before you display the Address Book:

[contacts setDisplayedProperties:[NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonEmailProperty]]];

As you can see, the setDisplayedProperties: method of the contacts object accepts an array of all the properties we want to display (see the part 1 about properties). In our example, we only need to display the contact’s e-mail addresses, so that’s the only one property we provide. Also, pay attention to the fact that the kABPersonEmailProperty is an int value, but the array accepts an object, so we create a NSNumber object based on this value. If you want to specify more properties to be displayed, just add them like the example line below. Remember that when you begin typing the kABPerson… the XCode automatically shows a list with all the available options you have, so it’s easy to find the kind of properties you look for. Also, you’ll use the [NSArray arrayWithObjects:...] instead of the [NSArray arrayWithObject:...].
Here is the same command, but this time we set the contacts object to display except for the e-mail addresses the phone numbers too:

[contacts setDisplayedProperties:[NSArray arrayWithObjects:[NSNumber numberWithInt:kABPersonEmailProperty], [NSNumber numberWithInt:kABPersonPhoneProperty], nil]];

The whole IBAction now should look like the next one (for demonstration, I list only some of the existing properties after our new command):

// Using this action we will allow the user to have access to device contacts.
-(IBAction)addContact{
    // Init the contacts object.
    contacts = [[ABPeoplePickerNavigationController alloc] init];

    // Set the delegate.
    [contacts setPeoplePickerDelegate:self];

    // Set the e-mail property as the only one that we want to be displayed in the Address Book.
    [contacts setDisplayedProperties:[NSArray arrayWithObject:[NSNumber numberWithInt:kABPersonEmailProperty]]];

    /*
     kABPersonBirthdayProperty
     kABPersonCreationDateProperty
     kABPersonDepartmentProperty
     kABPersonFirstNamePhoneticProperty
     kABPersonFirstNameProperty
     kABPersonJobTitleProperty
     kABPersonLastNamePhoneticProperty
     kABPersonLastNameProperty
     kABPersonMiddleNamePhoneticProperty
     kABPersonMiddleNameProperty
     kABPersonModificationDateProperty
     kABPersonNicknameProperty
     kABPersonNoteProperty
     kABPersonOrganizationProperty
     kABPersonPrefixProperty
     kABPersonSuffixProperty
     kABPersonPhoneProperty
     */

    // Preparation complete. Display the contacts view controller.
    [self presentModalViewController:contacts animated:YES];
}

Not a hard change, right?


Step 2

In this step we’ll add a new delegate method in our code. This is the next one:

-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{

   return NO;
}

When you tap on a property (for instance, on an e-mail address) into the window with the details of a contact, this is the method that’s been called, no matter whether you leave the Address Book or not.

A word now about that return NO at the end of the method. When the returned value is NO (false) then the Address Book gets dismissed after the user’s selection. If you turn the returned value into YES (true), then the Address Book doesn’t get dismissed when the user taps on a selection, the code inside the method (yes, we’ll put some code in there) is executed and the user continues to be navigated into the Address Book. In our example, we want the Address Book to go away when we tap on a property, so we’re leaving it as it is.


Step 3

That’s an easy one. Go to the other delegate method we implemented in our previous part of the tutorial and delete the code inside it. Yes, delete it. Even though the code that we’ll write inside our new delegate method will be the same in many points, we want to be clear now and to make sure that we will fully understand what we do in this example.

Set the returned value of the method to YES. So, it should look like this:

-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{

   return YES;
}

Step 4

In this step we’ll add the necessary code we need inside the new delegate method we created in the Step 2. Before I provide the code, there are a few things that I should talk about.

As I already said, when the user will tap on a contact, a new window with details will show up, displaying all the e-mail addresses of the specific contact. Inside this window, we want when the user taps on an e-mail address the Address Book to be dismissed and the selected e-mail to be shown in the table view. This task is a three-step job:

  1. We need to get the e-mail property as a multi-value. Remember that in the previous part of the tutorial we got the e-mails as an array (actually we copied the values into an array).
  2. From the total values of that multi-value we have to find the index of the selected e-mail only.
  3. Using this index we must copy the selected e-mail into a string.

For the three steps, we’ll use some new methods:

  1. For the first step we’ll use the ABRecordCopyValue method.
  2. For the second step we’ll use the ABMultiValueGetIndexForIdentifier method.
  3. For the third step we’ll use the ABMultiValueCopyValueAtIndex method.

You’ll watch all the above in action just in a while. Other than these, we’ll get the first and the last name of the contact and we will compose the full name (just like we did in the previous example). We will also save all data into an array, which is going to be stored into the contactsArray (again just like we did previously).

Here is the new delegate method complete with the new code inside it. Pay attention to the new commands that perform the three steps I described earlier:

-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier{

    // Get the first and the last name. Actually, copy their values using the person object and the appropriate
    // properties into two string variables equivalently.
    // Watch out the ABRecordCopyValue method below. Also, notice that we cast to NSString *.
    NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);

    // Compose the full name.
    NSString *fullName = @"";
    // Before adding the first and the last name in the fullName string make sure that these values are filled in.
    if (firstName != nil) {
        fullName = [fullName stringByAppendingString:firstName];
    }
    if (lastName != nil) {
        fullName = [fullName stringByAppendingString:@" "];
        fullName = [fullName stringByAppendingString:lastName];
    }

    // Get the multivalue e-mail property.
    CFTypeRef multivalue = ABRecordCopyValue(person, property);

    // Get the index of the selected e-mail.
    CFIndex index = ABMultiValueGetIndexForIdentifier(multivalue, identifier);

    // Copy the e-mail value into a string.
    NSString *email = (NSString *)ABMultiValueCopyValueAtIndex(multivalue, index);

    // Create a temp array in which we'll add all the desired values.
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];
    [tempArray addObject:fullName];

    // Save the email into the tempArray array.
    [tempArray addObject:email];

    // Now add the tempArray into the contactsArray.
    [contactsArray addObject:tempArray];

    // Release the tempArray.
    [tempArray release];

    // Reload the table to display the new data.
    [table reloadData];

    // Dismiss the contacts view controller.
    [contacts dismissModalViewControllerAnimated:YES];
    [contacts release];

    return NO;
}

Step 5

We are almost ready to go, apart from one last thing. We have to modify the table view and make it display only the full name and the selected e-mail. So, go into the - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath method and delete the following lines:

[[cell detailTextLabel] setNumberOfLines:2];
[[cell detailTextLabel] setText:[NSString stringWithFormat:@"%@\n%@", [[contactsArray objectAtIndex:currentRow] objectAtIndex:1], [[contactsArray objectAtIndex:currentRow] objectAtIndex:2]]];

Now copy-paste or type the next one:

[[cell detailTextLabel] setText:[[contactsArray objectAtIndex:currentRow] objectAtIndex:1]];

This command will display the e-mail address in the detailed text area of the cell.

That’s it. Now you can run and test the app, but first add some contacts into the Address Book of the Simulator with some e-mail addresses on them. Try to leave a contact without e-mail. You’ll notice when you’ll run the app that there is nothing to select from.

I hope this two-part tutorial to become handy and help you even a little. In here I’m just giving you a starting point to work with, but surely you can play around a lot with all the properties, methods, etc that the Address Book framework provides.

Here are some screenshots of our demo app.

Download the project here.

This tutorial was transferred as it was originally written in my blog, therefore some techniques, tools or SDKs may have changed since then.

How to import contacts from the Address Book – Part 1

It happens many times some of the iPhone apps we implement to need access to kind of information imported in ways other than the user’s input, or getting data from a file or downloading from the web. A kind of that information is the contacts info existing in the Address Book of the device.

Apple allows to access the Address Book database. That happens not directly, but through a couple of provided frameworks. Even though at the bottom line it’s proved easy to fetch contacts info (if you manage to do it once), on the other hand it’s not the most straightforward and the most documented part of the iPhone programming that someone may find.

So, in this two-part tutorial, I’ll try to explain in simple words how the whole mechanism works and of course, we’ll implement a demo app. Before we begin programming, we necessarily need to understand a couple of things. Consider this as a theoretical part before going into practice. I’ll try to present it as simple as possible, just to help you get the meaning.

Everyone who owns an iPhone uses the Address Book (the Contacts) in a daily basis and in the most of the cases, more than once per day. So, I guess that we’re all familiar with it and we know how it works. That’s important (especially for the user of your app), because whenever our app needs to access the contacts info, the Address Book window is loaded (with limited functionality of course) to allow navigation through the contacts and get all the info we need for the app. That also means that you don’t need to provide a custom interface to allow user to fetch contacts info. It’s provided by the frameworks you’ll use.

There are two things that we should always keep in mind when implementing apps that use the Address Book:

  1. First of all, you should know that there are two ways to import contact info into an app:
    • The first way is to just tap on a contact’s name and then return to your app, bringing with you all the info concerning that contact. When you’re back in your app, you may select what parts of the contact’s info you need. In this point let’s get realists, there is no way you need ALL that info, you’ll pick specific pieces of information only, except if you’re implementing your own address or phone book. Anyway, use this way only if you want to import into your app more than one pieces of information of a contact. This is what exactly we’ll discuss in this part of the tutorial.
    • The second way is to tap on a contact’s name and then go to a new window, where detailed info is provided. In there, you choose what you need for your app and then go back to it. We’ll discuss this case in the Part 2 of this tutorial.
  2. Secondarily, every piece of information concerning a contact is a property for the Address Book framework (ex. phone property, email property, etc). To be more accurate, the Address Book framework provides the ABPerson type, which is the structure of each contact. This type contains an enumerated list of all the properties, represented as kABPersonSOMETHINGProperty (ex. kABPersonPhoneProperty, kABPersonEmailProperty, kABPersonFirstNameProperty, etc). There are various different property types. These are:
    • kABStringPropertyType, for properties represented as string values.
    • kABIntegerPropertyType, for properties represented as integer values.
    • kABRealPropertyType, for properties represented as float values.
    • kABDateTimePropertyType, for properties represented as time or date values.

    Normally, you don’t need to distinguish the kind of each property, but you need to know the type of it in order to assign it to a proper variable type. Don’t worry, when you begin typing a property in the XCode the popup window will display all the properties beginning with the letters you type, where you may see the type of each property. Some pieces of contact info may contain more than one value. For example, a contact may have more than one e-mail addresses. In that case the returned value is not a single value, but a multi-value, which also means that you don’t store these properties into a single variable but into an array (NSArray). So, there are the following types of multivalues:

    • kABMultiStringPropertyType
    • kABMultiIntegerPropertyType
    • kABMultiRealPropertyType
    • kABMultiDateTimePropertyType

One final note. After selecting contacts info to import into your app and processing it, you don’t actually store the properties (their values) directly into variables or arrays. Instead, you copy them into the variables or arrays you want, using specific methods provided by the framework. No need to worry about it, you’ll see all that in action.

In my tutorials (as well as this one), I prefer giving practical solutions to programming problems and I don’t want to get you tired with theories. For that reason, I recommend some more reading about that topic to understand even more how all that stuff work. Personally, I recommend the “The iPhone Developer’s Cookbook” by Erica Sadun and the “Address Book Programming Guide for iOS” by Apple.

Ready to go to the real work? Let’s create the demo app first.


Step 1

Begin the XCode and create a Single View Application. Click on Next and give a name. I named the app ContactsTestApp. Save it somewhere in your disk and you’re ready.


Step 2

Let’s create the interface of our app. Open the ViewController.xib file in the Interface Builder. Add the next controls inside the view:

  • A Navigation Bar at the top. Give the title “Import Contacts Demo”.
  • A Bar Button Item at the right of the navigation bar. You may give it a name, I chose the “Add” Identifier (see the image below).
  • An UITableView (FRAME: X:0 Y:44 W: 320 H: 416).

If you created an interface like the one below, you’re on the right path:

ib


Step 3

We need to create and connect an outlet to the table view. We also need an array that will be used to display the imported data in the table view and of course, an IBAction that will let us add the contacts info into the app. So inside the ViewController.h file write these:

@interface ViewController : UIViewController
@property (nonatomic, retain) IBOutlet UITableView *table;
@property (nonatomic, retain) NSMutableArray *contactsArray;

-(IBAction)addContact;

Go to the interface builder and connect the outlet to the table view. Don’t forget to connect the table’s dataSource and delegate to the File’s owner. Also, connect the IBAction to the bar button item.

ib2

Let’s also synthesize the above properties. In the ViewController.m file write the following lines:

@synthesize table;
@synthesize contactsArray;

Release them as well in the dealloc method:

-(void)dealloc{
    [table release];
    [contactsArray release];
    [super dealloc];
}

So far we’re fine. We created and set up our demo app and we’re ready to go to what we’re really interested in.


Step 4

There are two frameworks that are necessary to exist in our project in order to work with the AddressBook. These are:

  • The AddressBook.framework
  • The AddressBookUI.framework

I’m sure you know how to import frameworks into a project. Go and import the above two into this project now (select the target project –> Build Phases –> Link Binary With Libraries –> Click on the plus sign (+) and in the new window that appears search for them).


Step 5

Inside the ViewController.h file, we need to import the appropriate libraries:

// Import the two next necessary libraries in the ViewController.h file.
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>

Also, in the interface header add the following delegate just like as you see it below:

@interface ViewController : UIViewController

Nice. Now, we need an object to access the address book. Again, inside the .h file:

// The contacts object will allow us to access the device contacts.
@property (nonatomic, retain) ABPeoplePickerNavigationController *contacts;

At this point the .h file you have should look like this:

#import <UIKit/UIKit.h>
// Import the two next necessary libraries in the ViewController.h file.
#import <AddressBook/AddressBook.h>
#import <AddressBookUI/AddressBookUI.h>

@interface ViewController : UIViewController
@property (nonatomic, retain) IBOutlet UITableView *table;
@property (nonatomic, retain) NSMutableArray *contactsArray;

// The contacts object will allow us to access the device contacts.
@property (nonatomic, retain) ABPeoplePickerNavigationController *contacts;

-(IBAction)addContact;

@end

We also need to synthesize the new property and release it in the dealloc method. Go into the ViewController.m file and add this:

@synthesize contacts;

Fill the dealloc method:

-(void)dealloc{
    [table release];
    [contactsArray release];
    [contacts release];
    [super dealloc];
}

Step 6

Until now, we created and setup the demo app, we imported the two necessary frameworks that are required and we also created an object of type ABPeoplePickerNavigationController (this is actually the Address Book modal view that will show up) to access the Address Book.

Our next task is to allow the user of our super-app to add contacts into it. So, we’ll implement the IBAction we declared earlier and you connected (I hope you did) to the add button in the Interface Builder.

Inside the ViewController.m file implement the addContact IBAction:

// Using this action we will allow the user to have access to device contacts.
-(IBAction)addContact{
    // Init the contacts object.
    contacts = [[ABPeoplePickerNavigationController alloc] init];

    // Set the delegate.
    [contacts setPeoplePickerDelegate:self];

    // Preparation complete. Display the contacts view controller.
    [self presentModalViewController:contacts animated:YES];
}

With the above method implemented, every time you tap (or click in the Simulator) on the add button, the Contacts modal view controller will show up, but nothing more yet. Even the Cancel button existing in the Contacts doesn’t work. Let’s work on that on the next step.


Step 7

We need to implement a couple of some delegate methods if we want the address book view controller to respond in our actions. At first, let’s make the addess book to dissappear when the user taps on the Cancel button. Inside the ViewController.m file add the following method:

// Implement this delegate method to make the Cancel button of the Address Book working.
-(void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker{
 [contacts dismissModalViewControllerAnimated:YES];
 [contacts release];
}

As you can see, the contacts view controller is dismissed and released.

Now it’s time for what we really want to do. We need when the user taps on a contact to fetch all its info, return back in our app and display only the data we want. In our example we’ll use these properties:

  • First name
  • Last name
  • Phone number
  • E-mail address

With the first two we’ll compose the full name. The next two are multi-values, which mean that they are returned more than one values (multiple phone numbers and multiple e-mails) and for the ease of our example we’ll get only the first values of the returned ones.

Once we fetch all the values we want, we’ll create an array with all of them. This array will be added in the contactsArray (the contactsArray is the array that will be used to store the data to be displayed in our table view, see later). This process is going to take place every time the user adds a contact into the app.

Add now the next delegate method into the ViewController.m file. The comments in it explain each step. Note that we actually copy the returned contact info into our variables instead of storing them directly.

-(BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person{
    // Get the first and the last name. Actually, copy their values using the person object and the appropriate
    // properties into two string variables equivalently.
    // Watch out the ABRecordCopyValue method below. Also, notice that we cast to NSString *.
    NSString *firstName = (NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
    NSString *lastName = (NSString *)ABRecordCopyValue(person, kABPersonLastNameProperty);

    // Compose the full name.
    NSString *fullName = @"";
    // Before adding the first and the last name in the fullName string make sure that these values are filled in.
    if (firstName != nil) {
        fullName = [fullName stringByAppendingString:firstName];
    }
    if (lastName != nil) {
        fullName = [fullName stringByAppendingString:@" "];
        fullName = [fullName stringByAppendingString:lastName];
    }

    // The phone numbers and the e-mails are contact info that have multiple values.
    // For that reason we need to get them as arrays and not as single values as we did with the names above.
    // Watch out the ABMultiValueCopyArrayOfAllValues method that we use to copy the necessary data into our arrays.
    NSArray *phones = (NSArray *)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonPhoneProperty));
    NSArray *emails = (NSArray *)ABMultiValueCopyArrayOfAllValues(ABRecordCopyValue(person, kABPersonEmailProperty));

    // Create a temp array in which we'll add all the desired values.
    NSMutableArray *tempArray = [[NSMutableArray alloc] init];
    [tempArray addObject:fullName];

    // Make sure that the selected contact has one phone at least filled in.
    if ([phones count] > 0) {
        // We'll use the first phone number only here.
        // In a real app, it's up to you to play around with the returned values and pick the necessary value.
        [tempArray addObject:[phones objectAtIndex:0]];
    }
    else{
        [tempArray addObject:@"No phone number was set."];
    }

    // Do the same for the e-mails.
    // Make sure that the selected contact has one email at least filled in.
    if ([emails count] > 0) {
        // We'll use the first email only here.
        [tempArray addObject:[emails objectAtIndex:0]];
    }
    else{
        [tempArray addObject:@"No e-mail was set."];
    }

    // Now add the tempArray into the contactsArray.
    [contactsArray addObject:tempArray];

    // Release the tempArray.
    [tempArray release];

    // Reload the table to display the new data.
    [table reloadData];

    // Dismiss the contacts view controller.
    [contacts dismissModalViewControllerAnimated:YES];
    [contacts release];

    return NO;
}

In the above method, did you see the return NO command at the end? That NO (false) means that the Contacts view controller should not continue into the selected contact’s details and should return in our app. If the method returns YES, then the view controller opens a new window with the contact’s details displayed on-screen. You’ll see this case in the second part of this tutorial. Also note that we manually dismiss the contacts view controller.

For the time being everything works fine, but nothing appears on the table view yet. In the next step we make our table view fully working.


Step 8

In our table, we’ll display the full name in the textLabel area of the cell and the phone number and e-mail in the detailTextLabel area. Note that we init each cell with the UITableViewCellStyleSubtitle parameter. Copy the next table view delegate methods into your code:

// Customize the number of sections in the table view.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
    return 1;
}

// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    return [contactsArray count];
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    static NSString *CellIdentifier = @"Cell";

    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
    if (cell == nil) {
        // Make sure to change the default style to the next one if you want to manage to display text
        // in the detailsTextLabel area.
        cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier] autorelease];
    }

    // Configure the cell.
    cell.selectionStyle = UITableViewCellSelectionStyleNone;

    // Specify the current row.
    int currentRow = [indexPath row];

    // Display the selected contact's info.
    // First the full name, then the phone number and finally the e-mail address.
    [[cell textLabel] setText:[[contactsArray objectAtIndex:currentRow] objectAtIndex:0]];

    // The rest info will be displayed in the detailsTextLabel of the cell.
    // Set the total number of lines to two (2).
    [[cell detailTextLabel] setNumberOfLines:2];
    [[cell detailTextLabel] setText:[NSString stringWithFormat:@"%@\n%@", [[contactsArray objectAtIndex:currentRow] objectAtIndex:1],
                                     [[contactsArray objectAtIndex:currentRow] objectAtIndex:2]]];

    return cell;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{
    return 60.0;
}

Everything is ready. You may try the app in the Simulator.

Below I give some screenshots of our app. I hope this how-to helped you to get the general idea when you want to work with the Address Book. Also, if you wish or if you need to, look at the second part of this tutorial, where we’ll get only a specific value from a contact inside the Address Book.

 

This tutorial was transferred as it was originally written in my blog, therefore some techniques, tools or SDKs may have changed since then.