How to import contacts from the Address Book – Part 2

Updated on July 6th, 2020

⏱ Reading Time: 6 mins

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:

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

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:

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

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

[objc]
// 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];
}
[/objc]

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:

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

return NO;
}
[/objc]

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:

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

return YES;
}
[/objc]


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:

[objc]
-(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;
}
[/objc]


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:

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

Now copy-paste or type the next one:

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

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.

Stay Up To Date

Subscribe to my newsletter and get notifiied instantly when I post something new on SerialCoder.dev.

    We respect your privacy. Unsubscribe at any time.