Address Book Tutorial in Swift and iOS

Address Book Tutorial in Swift and iOS
Meet our Furry Little Friends!

Meet our Furry Little Friends!

Update note: This tutorial was updated to Swift and iOS 8 by Niv Yahel. The original Objective-C tutorial was written by Tutorial Team member Evan Dekhayser.

Note: The contacts framework has changed significantly in iOS 9; this tutorial does not cover those changes. However this tutorial is still valuable if you wish to support iOS 8 and prior.

The Address Book framework allows you to read or modify the user’s contacts from your apps; these are the same contacts that show up in the Contacts app.

When using frameworks with Swift, not all of the ones you’ll encounter are object-oriented. Address Book has a C-based API, which doesn’t use objects; instead it uses opaque pointer-like types. In this Address Book tutorial, you’ll become familiar with a few of these:

  • ABAddressBookRef, the top-level collection of all the user’s contacts.
  • ABRecordRef, an individual contact record with properties such as name and company.
  • ABMultiValueRef and ABMutableMultiValueRef, which let you set properties of the ABRecordRef that may have multiple entries, such as phone number or email.

This Address Book tutorial assumes you are familiar with the basics of iOS development, and are comfortable with the basics of Swift. Let’s dive in and get some addresses!

Note: Apple has announced a new Contacts framework that will provide an object-oriented replacement to the Address Book API. That framework will be available when iOS 9 is released, which means you’ll need to continue using Address Book for your apps in the meantime.

Getting Started

To begin this tutorial, download the starter project that has the user interface pre-made, so you can stay focused on the Address Book part of the tutorial.

Build and run, and get ready to meet our furry little friends: Cheesy, Freckles, Maxi, and Shippo!


In this app, the user will press the image of one of the pets, and the pet’s contact information will be added to their address book (I’m surprised that even pets have iPhones!). Once added, you will be able to choose to add them to an “Animals” group to better contact them all in the future. Lastly, when tapping on an already added pet, you will be able to view and modify their information in a ABPersonViewController. Using the power of the Address Book API, you can finally contact your favorite furry friends.

Back in Xcode, open PetBookViewController.swift. The starter app has four UIButtons that all call tappedAddPetToContacts(_:) when pressed. If you look closely in the Utilities/Attributes Inspector in Main.storyboard, notice that each button has a different number in its tag. This will help you distinguish which button is the one that called tappedAddPetToContacts(_:).

To get started with the Address Book API, add the following line to the top of PetBookViewController.swift

import AddressBook

This will allow you to access the functions and types in the framework.

Asking for Permission

In 2012, there was a controversy regarding certain apps sending a copy of the user’s Address Book to its servers. Because of the public’s response to this security breach, Apple immediately implemented security features to prevent this from happening without the user’s knowledge.

So now, whenever you want to use the Address Book, you first ask the user for permission.

In PetBookViewController.swift, add the following code inside tappedAddPetToContacts(_:)

let authorizationStatus = ABAddressBookGetAuthorizationStatus()
switch authorizationStatus {
  case .Denied, .Restricted:
  case .Authorized:
  case .NotDetermined:
    println("Not Determined")

You can already see the lack of classes and objects here – to get the current authorization status, you call ABAddressBookGetAuthorizationStatus(). There are several different code paths depending on the return value here:

  1. This checks to see if the user has either denied your app access to the Address Book in the past, or if it is restricted because of parental controls. In this case, all you can do is inform the user that you can’t add the contact because the app does not have permission.
  2. This checks to see if the user has already given your app permission to use their Address Book. In this case, you are free to modify the Address Book however you want.
  3. This checks to see if the user hasn’t decided yet whether not to give permission to your app.

Build and run, and tap the cutest pet. You should see something like the following in the console:

PetBook[832:70b] Not Determined

You now know how to check the authorization status, but when you want something, you ask. Same thing here!

First, you need a reference to the user’s address book. Add the following property to the class:

let addressBookRef: ABAddressBook = ABAddressBookCreateWithOptions(nil, nil).takeRetainedValue()

ABAddressBookCreateWithOptions() will return a reference to the current address book. You don’t need to pass in any options or get an error handle back, so both parameters are nil.

Note: Some C APIs (including Address Book) haven’t been annotated by Apple, which prevents the compiler from automatically managing the memory of their objects. That means functions will often return Unmanaged objects, which as the name suggests, are unmanaged in terms of memory management.

Memory management is beyond the scope of this tutorial but what you’ll see throughout this project is calling takeRetainedValue() on returned references. This ensures the objects are retained and aren’t released from memory while you still might need to use them!

Now that you have a reference to the address book, add the following method to the class:

func promptForAddressBookRequestAccess(petButton: UIButton) {
  var err: Unmanaged<CFError>? = nil
  ABAddressBookRequestAccessWithCompletion(addressBookRef) {
    (granted: Bool, error: CFError!) in
    dispatch_async(dispatch_get_main_queue()) {
      if !granted {
        println("Just denied")
      } else {
        println("Just authorized")

ABAddressBookRequestAccessWithCompletion() will ask the user for access to the address book, and takes two arguments – the first is a reference to an address book, which you already have a property for. The second is a closure expression that will run once the user either allows or denies access.

You can see how granted is a Boolean passed into the closure to let you know which choice the user made. For now, you’ll just log out the results.

If you look at the documentation for ABAddressBookRequestAccessWithCompletion, the completion is called on an arbitrary queue. In other words, it may be called on a thread besides the main thread. Later on, you’ll be doing things such as showing alert dialogs so the closure expression starts with a dispatch to the main queue.

Head back to tappedAddPetToContacts(_:) and add the following line to the end of the .NotDetermined case:


That means you’ll prompt the user for permission the very first time they tap on a pet.

Build and run the app, and this time tap on the weirdest looking pet. A popup will appear to request access to the Address Book:


Depending on your choice, you’ll see either “Just authorized” or “Just denied” in the console. Now, tap an image again, and you’ll see the result is related to your action before: if you gave permission, it will say “Authorized”, or else it will say “Denied”.

Note: To test both cases, you can stop the app and then use the iOS Simulator/Reset Content and Settings option in the simulator app. This will clear out all the apps and settings in the simulator, allowing you to “re-install” the app and get a fresh start.

One issue with ABAddressBookRequestAccessWithCompletion() is that once the user gives the app permission, sometimes there is a 5-10 second delay until the completion is called. This can make it seem like the app’s frozen when it’s adding the contact. In most cases, this is not too much of an issue.

What happens if the user doesn’t allow access? Is your app stuck forever? Back in Xcode, add the following method to PetBookViewController:

func openSettings() {
  let url = NSURL(string: UIApplicationOpenSettingsURLString)

New in iOS 8 is the ability to send the user to the Settings app, right to the page with your app’s permissions. This method will do just that, using your app’s specific settings URL.

Next, you’ll need a method to show an alert and prompt the user to re-think their choice if they didn’t allow address book access. Add the following method to the class:

func displayCantAddContactAlert() {
  let cantAddContactAlert = UIAlertController(title: "Cannot Add Contact",
    message: "You must give the app permission to add the contact first.",
    preferredStyle: .Alert)
  cantAddContactAlert.addAction(UIAlertAction(title: "Change Settings",
    style: .Default,
    handler: { action in
  cantAddContactAlert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
  presentViewController(cantAddContactAlert, animated: true, completion: nil)

This method will tell the user that they can’t add the contact because the app doesn’t have the needed permissions. This will present a UIAlertController, which allows them either to continue or be directed to the settings page of the app by invoking openSettings().

Find promptForAddressBookRequestAccess(_:) and add the following line to the if block where you’re logging out “Just denied”:


Next, find tappedAddPetToContacts(_:) and add the following line to the end of the .Denied, .Restricted case:


Adding these method calls will show the alert if the user doesn’t allow access initially, and also when the user taps on a pet button after still not allowing access.

Use iOS Simulator/Reset Content and Settings to reset your simulator. Then build and run, tap the cutest pet, and deny permission. You should see the alert dialog appear, where you should tap “Change Settings” to be whisked away to the Settings app to correct your rejection of the cutest pet.


When you change the permission in the Settings app, your app will crash. Not to worry – this is just a simulator issue and you can just return to Xcode and run the app again.

Creating the Pet’s Record

The starter project already includes a Pet class that holds the pet details such as name, phone number and image. You’ll also see there’s some starter data stored in pet in PetBookViewController.

That’s just the data model for this app, but that doesn’t have anything to do with address book yet – now it’s time to move onto actually creating the records there. Add the following method to the class:

func makeAndAddPetRecord(pet: Pet) -> ABRecordRef {
  let petRecord: ABRecordRef = ABPersonCreate().takeRetainedValue()
  ABRecordSetValue(petRecord, kABPersonFirstNameProperty, pet.firstName, nil)
  ABRecordSetValue(petRecord, kABPersonLastNameProperty, pet.lastName, nil)
  ABPersonSetImageData(petRecord, pet.imageData, nil)

Given a Pet object, this method will eventually save a record to the address book. The call to ABPersonCreate() creates a reference to a new Address Book record. Once you have that, you can call ABRecordSetValue() and pass it the record, the field to change, and the value. To start off, you’re setting the first and last name fields.

Images are just as easy with ABPersonSetImageData() where you pass in the record and the image. Since the function is specific for the contact image, you don’t need to pass in the field.

There are plenty of attributes for a contact. As an exercise, store an e-mail for each of the pets!

Next, add the following code to the end of the method:

let phoneNumbers: ABMutableMultiValue =
ABMultiValueAddValueAndLabel(phoneNumbers, pet.phoneNumber, kABPersonPhoneMainLabel, nil)

Phone numbers are a bit trickier. Since one contact can have multiple phone numbers (home, mobile, etc.), you have to use ABMutableMultiValueRef, which supports multiple values.

When you declare the ABMutableMultiValueRef, you have to say what kind of property it will store. In this case, you want it to be for the kABPersonPhoneProperty. The second line adds the pet’s phone number, and you have to give this phone number a label. The label kABPersonPhoneMainLabel says that this is the contact’s primary number. You can find all of the phone number labels here.

That sets up the value with the phone number, but you still need to set it on the record. Can you figure out how to set the pet’s phone property yourself? If you get stuck, expand the spoiler below!

Solution Inside: Solution SelectShow
It is not that different from setting the name.

ABRecordSetValue(petRecord, kABPersonPhoneProperty, phoneNumbers, nil)

By now, you have created an ABRecordRef that has a first name, last name, phone number, and profile picture. However, it isn’t actually stored in the Address Book! Add the final bits of code to the end of makeAndAddPetRecord(_:):

ABAddressBookAddRecord(addressBookRef, petRecord, nil)
return petRecord

This will add the record, save the address book, and then return the newly created record. You haven’t implemented saveAddressBookChanges() yet – that’s next. Add the implementation to the class:

func saveAddressBookChanges() {
  if ABAddressBookHasUnsavedChanges(addressBookRef){
    var err: Unmanaged<CFErrorRef>? = nil
    let savedToAddressBook = ABAddressBookSave(addressBookRef, &err)
    if savedToAddressBook {
      println("Successully saved changes.")
    } else {
      println("Couldn't save changes.")
  } else {
    println("No changes occurred.")

This method will commit any unsaved changes to the address book. It also contains debug messages to let you know when changes couldn’t be saved or if there weren’t any changes to save.

To tie it all together, add ane more method to the class:

func addPetToContacts(petButton: UIButton) {
  let pet = pets[petButton.tag]
  let petRecord: ABRecordRef = makeAndAddPetRecord(pet)
  let contactAddedAlert = UIAlertController(title: "\(pet.firstName) was successfully added.",
    message: nil, preferredStyle: .Alert)
  contactAddedAlert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
  presentViewController(contactAddedAlert, animated: true, completion: nil)

In this method, you’ll pull up the appropriate Pet’s information as determined by the tag of the button. The tag conveniently matches up with the pet’s position in the pets array. You’ll use that information to create an ABRecordRef with the helper methods you just added, and then display an alert message.

Find promptForAddressBookRequestAccess(_:) and add the following line to the else block where you’re logging out “Just authorized”:


Next, find tappedAddPetToContacts(_:) and add the following line to the end of the .Authorized case:


These additions will call through to addPetToContacts(_:) when the user taps on a pet button – whether the app is already authorized, or needs authorization.

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.

Begin by adding the following to addPetToContacts(_:) after the first line of the method where you grab the appropriate Pet from the array:

if let petRecordIfExists: ABRecordRef = getPetRecord(pet) {

In this snippet of code, you are checking if the Pet exists as a contact already. If it does, you display and alert and exit the method early to skip the code that creates a record. This method invokes two helper methods getPetRecord(_:) and displayContactExistsAlert(_:), which you’ll add next:

func getPetRecord(pet: Pet) -> ABRecordRef? {
  let allContacts = ABAddressBookCopyArrayOfAllPeople(addressBookRef).takeRetainedValue() as Array
  var petContact: ABRecordRef?
  for record in allContacts {
    let currentContact: ABRecordRef = record
    let currentContactName = ABRecordCopyCompositeName(currentContact).takeRetainedValue() as String
    let petName = pet.description
    if (currentContactName == petName) {
      println("found \(petName).")
      petContact = currentContact
  return petContact

This method stores all of the contacts in an array using ABAddressBookCopyArrayOfAllPeople(), retrieves each contact’s name using ABRecordCopyCompositeName() and cross references it with the current Pet to see if it already exists. If it does, it will return the ABRecordRef of the contact.

Next, add the implementation for displayContactExistsAlert(_:):

func displayContactExistsAlert(petRecord: ABRecordRef) {
  let petFirstName = ABRecordCopyValue(petRecord, kABPersonFirstNameProperty).takeRetainedValue() as? String ?? "That pet"
  let contactExistsAlert = UIAlertController(title: "\(petFirstName) has already been added.",
    message: nil, preferredStyle: .Alert)
  contactExistsAlert.addAction(UIAlertAction(title: "OK", style: .Cancel, handler: nil))
  presentViewController(contactExistsAlert, animated: true, completion: nil)

This method uses ABRecordCopyValue() along with the kABPersonFirstNameProperty key to retrieve the first name of the contact. From there, it constructs an alert controller to let the user know the pet is already in the address book.

Build and 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.


Add a contact to group

The Address Book API allows you not only to store contacts but to add them to groups!. To start off, create the following method.

func createGroup(groupName: String) -> ABRecordRef {
  var groupRecord: ABRecordRef = ABGroupCreate().takeRetainedValue()
  let allGroups = ABAddressBookCopyArrayOfAllGroups(addressBookRef).takeRetainedValue() as Array
  for group in allGroups {
    let currentGroup: ABRecordRef = group
    let currentGroupName = ABRecordCopyValue(currentGroup, kABGroupNameProperty).takeRetainedValue() as! String
    if (currentGroupName == groupName) {
      println("Group exists")
      return currentGroup
  ABRecordSetValue(groupRecord, kABGroupNameProperty, groupName, nil)
  ABAddressBookAddRecord(addressBookRef, groupRecord, nil)
  println("Made group")
  return groupRecord

This method takes a String as a parameter, searches through an array of all existing groups for if the requested group exists. If it already exists, it will return its ABRecordRef. If not, it will create a group with this name and save the changes.

Notice how ABRecordSetValue() and ABRecordCopyValue() apply to groups as well? Contacts and groups are both ABRecordRef types; the trick is simply to know which ABPropertyID you need to use.

Now that you have the group record, you’ll need to check if a contact already belongs to a group, add them if they aren’t, and save the changes. Add the following method:

func addPetToGroup(petContact: ABRecordRef) {
  // 1
  let groupName = "Animals"
  let group: ABRecordRef = createGroup(groupName)
  // 2
  if let groupMembersArray = ABGroupCopyArrayOfAllMembers(group) {
    let groupMembers = groupMembersArray.takeRetainedValue() as Array
    for member in groupMembers {
      let currentMember: ABRecordRef = member
      if currentMember === petContact {
        println("Already in it.")
  // 3
  let addedToGroup = ABGroupAddMember(group, petContact, nil)
  if !addedToGroup {
    println("Couldn't add pet to group.")

Here’s what’s going on in this method:

  1. First, you get a reference to the “Animals” group using createGroup(_:), which you just added.
  2. If there are group members already, you loop through the list to see if the current pet is already in the group. If so, you log out a message and return early from the method.
  3. Otherwise, you add the pet to the group and save the changes.

You want to give the user the option to add the pet to the group after the pet is in the address book. Find displayContactExistsAlert(_:) and add the following code just after you initialize contactExistsAlert:

contactExistsAlert.addAction(UIAlertAction(title: "Add to \"Animals\" Group", style: .Default, handler: { action in

Find addPetToContacts(_:) and add the following similar code just after you initialize contactAddedAlert:

contactAddedAlert.addAction(UIAlertAction(title: "Add to \"Animals\" Group", style: .Default, handler: { action in

This code adds an additional button to the alerts shown when you tap on a pet for adding the pet to the new group.

Build and run your app. You will now be able to add a Pet to a group after adding it for the first time and after every subsequent tap.

Bonus: Displaying Contact Records

The Address Book framework has a complementary framework called AddressBookUI, which provides UI elements much like those found in the Contacts app. ABPersonViewController is one of them, which allows you to present a contact’s information in a Contacts-like manner, allowing you to modify their information and even make phone calls.

Luckily, AddressBookUI contains UI components and is object-oriented so you won’t see any Core Foundation references here! :]

To begin, add the following import to the top of PetBookViewController.swift:

import AddressBookUI

Find displayContactExistsAlert(_:) and add the following code right after the line that initializes contactExistsAlert:

contactExistsAlert.addAction(UIAlertAction(title: "Show Contact", style: .Default, handler: { action in
  let personViewController = ABPersonViewController()
  personViewController.displayedPerson = petRecord
  self.navigationController?.pushViewController(personViewController, animated: true)

That wasn’t so ruff. This action initializes a new ABPersonViewController object, which can display a single contact. You set the displayed record as the current pet record, and then push the view controller onto the navigation stack.

Build and run the app! Tap on a Pet that has already been added to your Address Book. You will now see “Show Contact” as an option. If you select that button, you’ll see the following:


You can modify any information and even make calls from this screen! Sorry, that’s not actually Cheesy’s phone number – she’s very private in real life. :]

Where To Go From Here?

Here is the finished example project from this Address Book tutorial.

In this tutorial, you learned how to create a new record, add it to a group, and present it using ABPersonViewController. You can do many other cool things with the Address Book API, such as display and modify pre-existing contacts – why not give that a try as an extension of this tutorial?

The AddressBookUI framework has several more convenient classes other than ABPersonViewController for modifying the address book. You could almost re-build the entire Contacts app with these classes, which offers even more opportunity for your own address book apps!

If you have any questions or comments regarding this tutorial or the Address Book API, please join the discussion in the comments below!

Address Book Tutorial in Swift and iOS is a post from: Ray Wenderlich

The post Address Book Tutorial in Swift and iOS appeared first on Ray Wenderlich.



Write a comment