Access the user's contacts and format and localize contact information.


The Contacts framework provides Swift and Objective-C API to access the user’s contact information. Because most apps read contact information without making any changes, this framework is optimized for thread-safe, read-only usage.

Working with the User’s Contacts

The Contacts framework is available on all Apple platforms and replaces the Address Book framework in iOS and macOS.

Contact Objects

The contact class (CNContact) is a thread-safe, immutable value object of contact properties, such as the contact’s name, image, or phone numbers.

Organizational diagram showing that a contact object has a mutable variant and can have properties that are represented as labeled value objects.

The contact class is like NSDictionary in that it has a mutable subclass CNMutableContact you can use to modify contact properties. For contact properties that can have multiple values, such as phone numbers or email addresses, an array of CNLabeledValue objects is used. The labeled value class is a thread-safe, immutable tuple of labels and values. Labels describe each value to the user, allowing differentiation such as home and work phone numbers. The Contacts framework provides some predefined labels and you can create your own custom labels.

Listing 1

Creating a contact

import UIKit
import Contacts
// Create a mutable object to add to the contact
let contact = CNMutableContact()

// Store the profile picture as data
let image = UIImage(systemName: "")
contact.imageData = image?.jpegData(compressionQuality: 1.0)

contact.givenName = "John"
contact.familyName = "Appleseed"

let homeEmail = CNLabeledValue(label: CNLabelHome, value: "" as NSString)
let workEmail = CNLabeledValue(label: CNLabelWork, value: "" as NSString)
contact.emailAddresses = [homeEmail, workEmail]

contact.phoneNumbers = [CNLabeledValue(
    label: CNLabelPhoneNumberiPhone,
    value: CNPhoneNumber(stringValue: "(408) 555-0126"))]

let homeAddress = CNMutablePostalAddress()
homeAddress.street = "One Apple Park Way" = "Cupertino"
homeAddress.state = "CA"
homeAddress.postalCode = "95014"
contact.postalAddresses = [CNLabeledValue(label: CNLabelHome, value: homeAddress)]

var birthday = DateComponents() = 1
birthday.month = 4
birthday.year = 1988  // (Optional) Omit the year value for a yearless birthday
contact.birthday = birthday

// Save the newly created contact
let store = CNContactStore()
let saveRequest = CNSaveRequest()
saveRequest.add(contact, toContainerWithIdentifier: nil)

do {
    try store.execute(saveRequest)
} catch {
    print("Saving contact failed, error: \(error)")
    // Handle the error

Formatting and Localization

The Contacts framework helps you format and localize contact information. For example, you can correctly format a contact name (using CNContactFormatter) or format an international postal address (using CNPostalAddressFormatter).

Listing 2

Formatting a name and postal address

// Formatting the contact name
let fullName = CNContactFormatter.string(from: contact, style: .fullName)
print("\(String(describing: fullName))")
// John Appleseed

// Formatting the postal address
let postalString = CNPostalAddressFormatter().string(from: homeAddress)
// One Apple Park Way
// Cupertino
// CA
// 95014

You can display localized object property names and predefined labels, based on the current locale setting of the device. Many objects defined in the Contacts framework, such as CNContact, include the localizedString(forKey:) method, which lets you get the localized version of a key name. In addition, the CNLabeledValue class includes the localizedString(forLabel:) method, which lets you get the localized label for the predefined labels in the Contacts framework.

Listing 3

Localizing a given name

// Device locale is Spanish
let displayName = CNContact.localizedString(forKey: CNContactNicknameKey)
// Prints "alias"

let displayLabel = CNLabeledValue<NSString>.localizedString(forLabel: CNLabelHome)
// Prints "casa"

Fetching Contacts

You can fetch contacts using the contact store (CNContactStore), which represents the user's contacts database. The contact store encapsulates all I/O operations and is responsible for fetching and saving of contacts and groups. Because the contact store methods are synchronous, it is recommended that you use them on background threads. If needed, you can safely send immutable fetch results back to the main thread.

The Contacts framework provides several ways to constrain contacts returned from a fetch, including predefined predicates and the keysToFetch property.

CNContact provides predicates for filtering the contacts you want to fetch. For example, to fetch contacts that have the name “Appleseed”, use predicateForContacts(matchingName:) and pass in Appleseed.

Listing 4

Fetching contacts using predicates

let predicate = CNContact.predicateForContacts(matchingName: "Appleseed")

Note that generic and compound predicates are not supported by the Contacts framework.

You can use keysToFetch to limit the contact properties that are fetched. For example, if you want to fetch only the given name and the family name of a contact, you specify those contact keys in a keysToFetch array.

Listing 5

Fetching contacts using KeysToFetch

let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey] as [CNKeyDescriptor]

To fetch a contact using both a predicate (predicateForContacts(matchingName:)) and a keysToFetch array, use unifiedContacts(matching:keysToFetch:).

Listing 6

Fetching contacts using a predicate and an array of contact attributes

let store = CNContactStore()
do {
    let predicate = CNContact.predicateForContacts(matchingName: "Appleseed")
    let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keysToFetch)
    print("Fetched contacts: \(contacts)")
} catch {
    print("Failed to fetch contact, error: \(error)")
    // Handle the error

The Contacts framework can also perform operations on the fetched contacts, such as formatting contact names. Each operation requires a specific set of contact keys to correctly perform the operation. The keys are specified as key descriptor objects that must be included within the keysToFetch array. For example, if you want to fetch the contact’s email addresses and also be able to format the contact’s name (using CNContactFormatter), include both CNContactEmailAddressesKey and the key descriptor object returned by descriptorForRequiredKeys(for:) in the keysToFetch array.

Listing 7

Fetching contacts with key descriptors

let keysToFetch = [CNContactEmailAddressesKey as CNKeyDescriptor, CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]


Users can grant or deny access to contact data on a per-app basis. Any call to CNContactStore will block the app while the user is being asked to grant or deny access. Note that the user is prompted only the first time access is requested; any subsequent CNContactStore calls use the existing permissions. To avoid having your app’s UI main thread block for this access, you can use either the asynchronous method requestAccess(for:completionHandler:) or dispatch your CNContactStore usage to a background thread.

Partial Contacts

A partial contact has only some of its property values fetched from a contact store. All fetched contact objects are partial contacts. If you try to access a property value that was not fetched, you get an exception. If you are unsure which keys were fetched in the contact, it is recommended that you check the availability of the property values before you access them. You can either use isKeyAvailable(_:) to check the availability of a single contact key, or areKeysAvailable(_:) to check multiple keys. If the desired keys are not available then refetch the contact with them.

Listing 8

Checking the availability of a key

// Check if the phone number is available for the given contact
if contact.isKeyAvailable(CNContactPhoneNumbersKey) {
} else {
    //Refetch the keys
    let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] as [CNKeyDescriptor]

    do {
        let refetchedContact = try store.unifiedContact(withIdentifier: contact.identifier, keysToFetch: keysToFetch)
    } catch {
        print("Failed to fetch contact, error: \(error)")
        // Handle the error

Unified Contacts

Contacts in different accounts that represent the same person may be automatically linked together. Linked contacts are displayed in macOS and iOS apps as unified contacts. A unified contact is an in-memory, temporary view of the set of linked contacts that are merged into one contact.

Diagram that shows a person's iCloud and social media account contact information combined into a single, unified contact.

By default the Contacts framework returns unified contacts. Each fetched unified contact (CNContact) object has its own unique identifier that is different from any individual contact’s identifier in the set of linked contacts. A refetch of a unified contact should be done with its identifier.

Saving Contacts

The contact store (CNContactStore) is also used to save changes to the Contacts framework objects. The CNSaveRequest class enables save operations and allows batching of changes to multiple contacts and groups into a single operation. After all objects are added to the save request, it can be executed with a contact store as shown Listing 9 code listing below. Do not access the objects in the save request while the save is executing, because the objects may be modified.

Listing 9

Saving a new contact

// Create a new contact
let newContact = CNMutableContact()
newContact.givenName = "John"
newContact.familyName = "Appleseed"

// Save the contact
let saveRequest = CNSaveRequest()
saveRequest.add(newContact, toContainerWithIdentifier: nil)

do {
    try store.execute(saveRequest)
} catch {
    print("Saving contact failed, error: \(error)")
    // Handle the error
Listing 10

Saving a modified contact

// Update the home email address for John Appleseed
guard let mutableContact = contact.mutableCopy() as? CNMutableContact else { return }
let newEmail = CNLabeledValue(label: CNLabelHome, value: "" as NSString)

let saveRequest = CNSaveRequest()
do {
    try store.execute(saveRequest)
} catch {
    print("Saving contact failed, error: \(error)")
    // Handle the error

Contacts Changed Notifications

After a save is successfully executed, the contact store posts a CNContactStoreDidChange notification to the default notification center. If you cache any Contacts framework objects you need to refetch those objects, either by their identifiers, or with the predicates that were used to originally fetch them, and then release the cached objects. Note that cached objects are stale, but not invalid.

Containers and Groups

A user may have contacts in their device’s local account or server accounts configured to sync contacts. Each account has at least one container of contacts. A contact can be in only one container.

Diagram that shows a person's contacts separated into a container for iCloud contacts and a container for social media account contacts.

A group is a set of contacts within a container. Not all accounts support groups and some accounts support subgroups. An iCloud account has only one container and may have many groups but no subgroups. On the other hand, an Exchange account does not support groups, but may have multiple containers representing Exchange folders.

Diagram that shows groups within containers of contacts.



Requesting Authorization to Access Contacts

Request permission from the user to read, create, and modify their Contacts entries.

class CNContactStore

The object that fetches and saves contacts, groups, and containers from the user's contacts database.

property list key NSContactsUsageDescription

A message that tells the user why the app is requesting access to the user’s contacts.

Name: Privacy - Contacts Usage Description

A Boolean value that indicates whether the app may access the notes stored in contacts.

Contact Data

class CNContact

An immutable object that stores information about a single contact, such as the contact's first name, phone numbers, and addresses.

class CNMutableContact

A mutable object that stores information about a single contact, such as the contact's first name, phone numbers, and addresses.

Data Objects

Access contact-related data, such as the user's postal address and phone number.

Contact Keys

Specify contact-related properties during fetch operations.

Fetch and Save Requests

class CNContactFetchRequest

An object that defines the options to use when fetching contacts.

class CNSaveRequest

An object that collects the changes you want to save to the user's contacts database.


class CNContactFormatter

An object that you use to format contact information before displaying it to the user.

class CNPostalAddressFormatter

An object that you use to format a contact's postal addresses.

class CNContactVCardSerialization

An object you use to convert to and from a vCard representation of the user's contacts.

class CNContactsUserDefaults

An object that defines the default options to use when displaying contacts.


Error Information

Diagnose errors generated by the Contacts framework.