Address Book Tutorial in iOS
In this Address Book Tutorial in iOS, learn how to add and edit contacts in a fun app about pets. By Evan Dekhayser.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Address Book Tutorial in iOS
20 mins
Creating the Pet’s Record
Now it’s time to move onto actually creating the records. Underneath petTapped:, create a new method called addPetToContacts:
- (void)addPetToContacts: (UIButton *) petButton{
}
In this method, you’ll create an ABRecordRef
with the pet’s attributes, check the address book to make sure the pet does not already exist, and if the pet is not in the Address Book, add it to the user’s contacts.
Begin addPetToContacts:
with the following.
NSString *petFirstName;
NSString *petLastName;
NSString *petPhoneNumber;
NSData *petImageData;
if (petButton.tag == 1){
petFirstName = @"Cheesy";
petLastName = @"Cat";
petPhoneNumber = @"2015552398";
petImageData = UIImageJPEGRepresentation([UIImage imageNamed:@"contact_Cheesy.jpg"], 0.7f);
} else if (petButton.tag == 2){
petFirstName = @"Freckles";
petLastName = @"Dog";
petPhoneNumber = @"3331560987";
petImageData = UIImageJPEGRepresentation([UIImage imageNamed:@"contact_Freckles.jpg"], 0.7f);
} else if (petButton.tag == 3){
petFirstName = @"Maxi";
petLastName = @"Dog";
petPhoneNumber = @"5438880123";
petImageData = UIImageJPEGRepresentation([UIImage imageNamed:@"contact_Maxi.jpg"], 0.7f);
} else if (petButton.tag == 4){
petFirstName = @"Shippo";
petLastName = @"Dog";
petPhoneNumber = @"7124779070";
petImageData = UIImageJPEGRepresentation([UIImage imageNamed:@"contact_Shippo.jpg"], 0.7f);
}
By looking at the button the user chose, you can determine which pet was selected. If the user pressed Shippo, then you want the user to have Shippo’s contact information. The only thing that may be unfamiliar here is UIImageJPEGRepresentation()
, which takes a UIImage and returns an NSData representation of it.
Next, type this at the end of addPetToContacts:
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, nil);
ABRecordRef pet = ABPersonCreate();
The first line creates the ABAddressBookRef
that will add the pet to the user’s contacts later. The second line creates an empty record for your app to fill with the pet’s information.
Next, set the pet’s first and last names. This code will look like this.
ABRecordSetValue(pet, kABPersonFirstNameProperty, (__bridge CFStringRef)petFirstName, nil);
ABRecordSetValue(pet, kABPersonLastNameProperty, (__bridge CFStringRef)petLastName, nil);
A quick explanation:
-
ABRecordSetValue()
takes anABRecordRef
as its first parameter, and that record ispet
. - The second parameter calls for an
ABPropertyID
, which is a value defined by the API. Because you want to set the first name, you passkABPersonFirstNameProperty
. - For the last name, similarly pass
kABPersonLastNameProperty
.
Does the third argument seem confusing? What it does is take a CFTypeRef
, which is the broad type that includes CFStringRef
and ABMultiValueRef
. You want to pass a CFStringRef
, but you only have an NSString
!
To convert an NSString
to a CFStringRef
, you have to bridge it using (__bridge CFStringRef) myString;
. If you are familiar with “casting the variable,” it is similar to that.
Note: For more information on the __bridge
keyword, check out Chapters 2 and 3 in iOS 5 by Tutorials, Beginning and Intermediate ARC.
Note: For more information on the __bridge
keyword, check out Chapters 2 and 3 in iOS 5 by Tutorials, Beginning and Intermediate ARC.
Phone numbers are a bit trickier. Since one contact can have multiple phone numbers (home, mobile, etc.), you have to use ABMutableMultiValueRef
. This can be done by adding the following code to the end of addPetToContacts:
.
ABMutableMultiValueRef phoneNumbers = ABMultiValueCreateMutable(kABMultiStringPropertyType);
ABMultiValueAddValueAndLabel(phoneNumbers, (__bridge CFStringRef)petPhoneNumber, kABPersonPhoneMainLabel, NULL);
When you declare the ABMutableMultiValueRef
, you have to say what kind of property it will. In this case, you want it to be for the kABPersonPhoneProperty
. The second line adds the pet’s phone number (which is bridged to CFTypeRef
), and you have to give this phone number a label. The label kABPersonPhoneMainLabel
says that this is the contact’s primary number.
Try setting the pet’s phone property yourself. If you get stuck, expand the field below!
[spoiler title=”Solution”]It is not that different from setting the name.
ABRecordSetValue(pet, kABPersonPhoneProperty, phoneNumbers, nil);
[/spoiler]
The last piece of information to add to the record is its picture — you definitely want to see that adorable face when they call to ask for treats!
To set the record’s image, you use this statement:
ABPersonSetImageData(pet, (__bridge CFDataRef)petImageData, nil);
To add this contact and save the address book, use the following two short lines:
ABAddressBookAddRecord(addressBookRef, pet, nil);
ABAddressBookSave(addressBookRef, nil);
As a final step, you need to call this new method in the appropriate spots. So add this line of code in sections 2 and 5 inside petTapped::
[self addPetToContacts:sender];
Use iOS Simulator/Reset Content and Settings to reset your simulator, build and run, and tap on each of the pets. If asked, give the app permission to use the Address Book.
Once you’re done, go to the home screen (use Cmd+Shift+H to do this in the simulator), and go to the Contacts app. You should see the pets!
Duplicates? No More!
There are still a few things to fix up. First, you may have noticed that if you tap a pet twice, two entries will appear in the contact list. But there can only be one Shippo! ;]
To prevent Shippo clones, you should iterate through all the contacts and make sure that the new contact’s name is not in the address book already.
Insert the following sections of code before the ABAddressBookAddRecord()
and ABAddressBookSave
calls.
First, add this line to get an NSArray
of the Address Book’s contacts.
NSArray *allContacts = (__bridge NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBookRef);
Notice how you use __bridge
going to NSArray in this case. It goes both between Core Foundation –> Foundation and Foundation –> Core Foundation.
Next, add this line to iterate through the array so that you can check the name of every record.
for (id record in allContacts){
ABRecordRef thisContact = (__bridge ABRecordRef)record;
if (CFStringCompare(ABRecordCopyCompositeName(thisContact),
ABRecordCopyCompositeName(pet), 0) == kCFCompareEqualTo){
//The contact already exists!
}
}
You have to use id
because technically Core Foundation types can’t be in an NSArray, because they are not objects. The ABRecordRefs are disguised as id
’s to avoid errors. To get the ABRecordRef, simply __bridge
again!
The way you use CFStringCompare
here is similar to using NSString’s isEqualToString:
ABRecordCopyCompositeName
gets the full name of the record by joining the contact’s first and last names.
Finally, add the following to the if statement:
UIAlertView *contactExistsAlert = [[UIAlertView alloc]initWithTitle:[NSString stringWithFormat:@"There can only be one %@", petFirstName] message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[contactExistsAlert show];
return;
This shows an alert to the user and stops the method so the contact isn’t added. If the loop goes through all the contacts and does not find a match, it adds the pet to the Address Book.
Run the app, and try to select one of the pets multiple times. Look for an alert that says the contact already exists to appear.
It’s also helpful if you add an alert whenever the contact is added. At the end of this method, after the app adds and saves the contact, insert this confirmation alert:
UIAlertView *contactAddedAlert = [[UIAlertView alloc]initWithTitle:@"Contact Added" message:nil delegate:nil cancelButtonTitle:@"OK" otherButtonTitles: nil];
[contactAddedAlert show];