Address Book Tutorial in Swift and iOS

In this Address Book Tutorial for iOS, learn how to add, edit and display contacts in a fun app about pets. By Niv Yahel.

Leave a rating/review
Save for later
Share
You are currently viewing page 2 of 3 of this article. Click here to view the first page.

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.

Note:
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 =
  ABMultiValueCreateMutable(ABPropertyType(kABMultiStringPropertyType)).takeRetainedValue()
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!

[spoiler title=”Solution”]It is not that different from setting the name.

ABRecordSetValue(petRecord, kABPersonPhoneProperty, phoneNumbers, nil)

[/spoiler]

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)
saveAddressBookChanges()

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”:

self.addPetToContacts(petButton)

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

addPetToContacts(petButton)

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!

PetBook-AllContacts

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) {
  displayContactExistsAlert(petRecordIfExists)
  return
}

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.

PetBook-ContactExists

Niv Yahel

Contributors

Niv Yahel

Author

Over 300 content creators. Join our team.