Introducing the Contacts Framework for iOS and OS X
Whether it's getting contact information, managing a social graph, or adding a new friend, Contacts are a critical piece of many apps. OS X El Capitan and iOS 9 now share a new Contacts API. Understand the design, goals, and benefits of this new framework. Gain critical insights into how to make a smooth transition for your app to this new framework.
BRUCE STADNYK: Good afternoon!
I am Bruce Stadnyk from the iOS contacts team and I'm excited
to introduce the new Contacts Framework to you.
BRUCE STADNYK: If you are new
to Apple's platforms you will learn how easy it is
to use contacts in your app.
If you are an experienced developer with Address Book,
you will love this new Framework.
So what is this new Contacts Framework?
Well, we have been listening to your Address Book feedback
and today we are addressing the most frequent request.
The Address Book Framework provides an Objective-C API
to access contacts, and the API is designed
to work well with Swift
BRUCE STADNYK: We are as excited about this as you are.
There are many design goals with this new Contacts Framework.
I'm going to review a few of the key ones with you now.
One, to address the majority of apps
that are mostly get contacts and do not modify contacts,
we have designed the API for thread safe read-only usage.
This is done mostly with immutable value objects
that do not reference a data store.
This allows you to pass contacts easily between queues
on your app and not have unexpected I/O occur on them.
Another is to have the same contacts API
on OS X, iOS and watchOS.
BRUCE STADNYK: You learn one API and then use the same code
to access contacts across multiple Apple platforms.
And, Address Book, if you are using it,
it is being deprecated.
[ Cheers and applause ]
BRUCE STADNYK: We don't realize how much we take
for granted the contacts on our devices.
For example when we receive a phone call
and we only see a phone number, we ask ourselves: Who is that?
Is it someone from our family?
Is it a friend?
It is a much better experience when a contact is displayed.
Oh, it's John Apleseed, one of my best friends.
So everyone has contacts on their devices.
They help us to identify who we are communicating with
and also help us to make phone calls, send e-mails,
and initiate other means of communication.
For example, I can speak to my device and say: Hey,
Siri, call John Appleseed.
Okay. There we go.
SIRI: Calling John Appleseed, iPhone on speaker.
BRUCE STADNYK: So contacts are a central part
of the user experience on our devices.
So how does the Contacts Framework handle this
Let's take a look at an example with John Appleseed.
For those of you experienced with Address Book,
this is a quick review.
Here we have John's profile picture, his first name,
last name, his home e-mail address, work e-mail address,
and the phone number for his iPhone.
These contact properties represent this
The profile image is represented by image data.
The name is broken into components.
So the first name is represented by given name
and the last name by family name.
Both the home and work e-mail addresses are represented
by e-mail addresses.
And the phone number is represented by phone numbers.
There are many more contact properties.
You can refer to the contacts documentation for more details.
Now, let's talk more about this object.
This is the CNContact object.
It is an immutable value object of contact properties.
It is modeled like NSDictionary.
It has a mutable subclass, CNMuteableContact,
that you modify the contact properties with.
You will see this pattern throughout the
For contact properties that can have multiple values
like e-mail addresses, or phone numbers,
an array of CNLabeledValue is used.
CNLabeledValue is an immutable Tuple of label and value,
where the label is a string, and the value is an object.
Like string for an e-mail address.
The value can be labeled to help differentiate it
from the multiple values for a property,
such as a home e-mail address, or a work e-mail address.
For those of you experienced with Address Book,
AB multivalue is replaced by this array of CNLabeledValue.
Yes, you heard that correctly, AB multivalue is dead.
BRUCE STADNYK: Now I would like to take a look
at an example of creating a new contact with John Appleseed.
So first we import Contacts,
then we create a mutable contact,
as we are going to be adding to it.
We then set John's profile picture as NSData to imageData,
and then we set his name to givenName and familyName.
Now, for John's two e-mail addresses,
we create two CNLabeled values, one with CNLabelHome,
the other with CNLabelWork.
These are some of the predefined labels
in the Contacts Framework.
These predefined labels have localized strings
that you can use in your apps UI.
You can also create your own custom labels.
We take these two label values, home e-mail and work e-mail,
place them in an array, and set them on e-mail addresses.
It's that simple.
And we can do the same thing with John's phone number.
Again, we create a CNLabeled value,
use the iPhone predefined label, create a CNPhoneNumber object
as the value, place the label value in array,
and set that to phone numbers.
I also know John's home address, so I can add that as well.
I create a CNMuteablePostalAddress,
set the appropriate information,
again create a labeled value using LabelHome,
place that in array, and set that to postal addresses.
Finally, I also know his birthday,
so I can create an NSDateComponent, set the day,
month, and year component,
and set that to the birthday property.
Note that all date-related properties
in the Contacts Framework are NSDate components.
This allows flexibility to have dates
such as year-less birthdays,
where you would omit the year component.
The Contacts Framework is also able to perform operations
on these contact objects.
Of interest here is formatting contact data.
The CNContactFormatter will format a contact's name.
In this example, we're formatting the full name,
and get back John Appleseed.
CNContact Formatter will correctly format
We also have a formatter, CNPostalAddressFormatter
for formatting mailing labels for postal addresses.
That returns back...that.
CNPostalAddressFormatter will correctly format international
We recommend that you use these Formatters
in your app when appropriate.
Now, I would like to invite Dave up to the stage
to show you how you can use Contacts in your app.
DAVE DRIBIN: Thank you, Bruce.
My name is Dave Dribin, and I work on the OS X Contacts team.
Sorry. So Bruce just showed you how to create
and modify CNContact objects in code.
However, these already has many contacts as part
of the Contacts app of OS X, iOS and watchOS.
And Bruce also showed how system apps can integrate
with these contacts to provide a richer user experience.
For example, the phone app can show the person's name
and photo instead of just a phone number,
for an incoming phone call.
The Contacts Framework allows you to provide
that same rich experience for your app.
So the class you are going to use
to access a user's contacts is called CNContactStore.
We are going to talk about how to fetch
and save users' contacts.
Let's start off with fetching.
The main method you are going
to use is called unified ContactsMatchingPredicate,
This is going to return an array of CNContact objects.
The predicate in Keys to Fetch are there in order
to help your app fetch as efficiently as possible.
Let's start off with the predicate.
The user might have hundreds, or even thousands of contacts.
You might only be interested in a small subset of those.
The predicate allows you to, ah,
helps you limit the number of results returned.
Now, for those that don't know,
NSPredicate is a standard foundation-level object
that presents criteria to be matched
against an object while searching.
The Contacts Framework provides predicates you can use
with the contact store.
And the contacts store will evaluate these
against the predicate, or the contact.
The example here is predicate ForContactsMatchingName.
And this will match each of the contacts
against the specified name, in this case Appleseed.
Let's see a quick example.
Say the user has these three contacts.
John Appleseed, Jane Appleseed, and Craig Bromley.
The contacts store can effectively evaluate this
predicate [John Appleseed] against each
of the contacts [Jane Appleseed; Craig Bromley]
and only return the matching ones.
In this case John and Jane are going
to be returned, but not Craig.
So the predicate allows you to limit the number
of contacts returned, but there's still a lot
of contact information on a contact,
and you might only be interested in a small subset of that,
and that's where keysToFetch comes in.
KeysToFetch is an array of strings.
And these are strings of keys, in the key-value-coding sense.
So if you are just interested in the given name and family name,
you could set up your keysToFetch like this.
Of course, using string literals is error prone.
We provide constants for this.
And what the Contact Store is going to do is it's only going
to fetch the properties that you specify.
In this case, given name and family name.
So you can really see how the predicate
in keysToFetch allows you to scope down the amount
of information to returned so that your app can be
as efficient as possible.
Let's go over a full example.
So here we are going to start off with a predicate
and keysToFetch as we had earlier,
but now you need a contacts store to use these on.
And this is easy, you can just create one
with the default initializer.
Then you call unified ContactsMatchingPredicate,
keysToFetch with those values, and assuming this works,
you're going to get back an array of contacts,
and then you can use them however you want.
Here we are just going to print
out the given name and family name.
There's a couple of important things I want
to talk about, about fetching.
The first one is that the lifetime
of a CNContact is not tied
to the lifetime of a CNContact store.
There is no need to keep a strong reference to the Store
around after the fetch completes.
It means the data on the CNContact is, ah,
valid and it is from the time of the fetch, basically a snapshot
from the time of the fetch, and it is valid
for the lifetime of that CNContact.
And the second important thing,
is that this is a synchronous method,
and fetching contacts is a relatively slow operation.
As such, you should really fetch these on a background queue,
to keep your user interface responsive.
And as Bruce mentioned earlier,
CNContacts are completely thread safe, so it's safe to take these
from the background queue, and move them over to the main queue
to update your user interface.
And another really good reason to fetch
on a background queue is data privacy.
So, users take the privacy of their contacts very seriously.
And as such, we want to put up a barrier between your app,
and the users contacts.
The very first time your app accesses contacts
through the API, the OS is going to show a dialogue box
or alert asking the user to allow or deny access.
You have probably seen these before.
This means that the first time you call a method
on the contacts store, it cannot provide the results
until the user responds, and that can be a long time.
So while you can move your contacts store access off
to a background queue using GCD or NS operation,
we provide a helper method here,
an async method called request access
for entity type completion handler.
Now the user may deny access, and your app should be able
to handle this gracefully.
And if the user allows access,
be sure to handle this contact data with care.
Please see the privacy in your app session
for more information.
I would like to talk a little bit more about keysToFetch
and how they return partial contacts.
So as I showed previously, the keysToFetch allows you
to only fetch the properties you are interested in.
In this case the given name and family name.
What if you tried to access a property you didn't request--
for example a phone number?
It's going to throw an exception,
because that data is not there,
and we call these partial contacts because only some
of the properties are available.
Now normally this isn't a problem if you set
up your keysToFetch properly,as we did in the previous examples,
but there are times you are going to get a contact,
and you are unsure
which keysToFetch was used when it was fetched.
In those cases, you are going to want to check to see
if the key is available before accessing the property,
just as you would check the length
of an array before indexing into it, to avoid an exception.
Here this example is using the isKeyAvailable method to see
if the PhoneNumbers key is available
for accessing the phone numbers property.
You might be thinking "well, that's great,
but I really wanted to access those phone numbers."
In those cases, you can re-fetch the contact
with the additional keysToFetch.
Let's see how that would work.
So, here we are setting up keysToFetch,
but this time we're using the phone numbers key,
and using a method called unifiedContactWithIdentifier.
Now each contact has a identifier
that uniquely identifies it, and you can use to re-fetch
at a later point in time.
And then, once you re-fetch,
you can safely access the phone numbers
on this re-fetched contact.
In partial contacts it's important
to understand how they work with the rest of the framework.
Now, the previous example showed how we fetched the given name
and family name and then printed them out,
to print the full name, but that's really not ideal.
We should really use one of the formatters, sorry,
the CNContact formatter that Bruce showed earlier,
and the formatter may access other properties
that you haven't fetched, like name, prefix, or suffix.
If they're not there, it's going to throw an exception.
So, we could document all the keys you need in order
to use the formatter, but that's rather tedious and error prone.
So we've come up with the concept of key descriptors.
And key descriptors represent a set of keys
for a particular operation.
In this case, the formatter knows which keys it needs
to do its job, so it is providing the key descriptors
with the descriptor ForRequiredKeysForStyle method,
and you can include this directly in your keys to fetch.
And this tells the contact store all of the properties
that it needs to fetch for the formatter.
Let's see an example of this.
So in this example, we want to fetch all contacts
with the name Appleseed,
and we want to print their full name and e-mail addresses.
We are going to set up the predicate as we did before,
and set up the keysToFetch a little bit differently.
We are going to start off with descriptor for required keys
for style (.FullName).
And this is going to, uh, allows us to get the full name,
using the Contact Formatter later on.
You can also include the CNContact e-mail addresses key,
because we want to print the e-mail addresses.
You can intermix key descriptors
and CNContact keys in the same array.
With this setup, you fetch, just as we did before,
calling unified contacts matching predicate,
and then with the results, you can get the full name
with the formatter and the e-mail addresses.
So one other important point
about fetching is unified contacts.
You may have the same contact in multiple accounts.
For example, you might have a John Appleseed
in your iCloud account with his work e-mail address
and phone number, but you might also be friends
with John on Facebook.
And that is going to have an image,
home e-mail address, and birthday.
So rather than display two separate contacts there,
the contacts app is going to use some heuristics
to link these together, and display a single contact
with the union of the information,
and we call these unified contacts.
And contacts apps have been doing this
for a few releases now.
The Contacts Framework will return unified contacts
by default, as you may have guessed from the method names.
So the good news is, that means that you're going
to get the data back that the user sees in the app.
The really great thing here is
that these are ordinary CNContact objects, and they work
and act just like any other CNContact object.
you can even modify them and save them and it will just work.
So speaking of saving, let's go over a few code examples
on how to save contacts.
I'm going to start off by adding a new contact.
So let's say you've got a C immutable contact,
and you set it up with data, as Bruce showed you earlier.
In order to get this into the user's contacts, you are going
to use what's called a save request, and you are going
to execute that save request on a contact store.
The first thing you do is create a new CNSaveRequest object,
and then you are going to call add contact,
to container with identifier.
Now we don't have time to talk about containers,
but the nil container identifier means the default container,
and, so please refer
to the documentation for more information.
And save request just marks a contact for being added.
It doesn't actually apply this change yet.
For that you need to call execute SaveRequest
on a contacts store.
Assuming this completes successfully, this will be added
to the user's contacts.
Updating an existing contact is very similar,
but now you are going to be starting off with, say,
an immutable contact that you got from a fetch.
So, the first thing you are going to want
to do is create a mutable copy,
and then make any changes you want.
For example, here we are adding in a new e-mail address.
Now, it is important to note that,
when you make a mutable copy of a partial contact,
only modify the property that you had fetched.
And just as before, we need to use a save request.
Create a new save request, but this time we are going
to use the updateContact method.
And again, this just marks the contact for being updated,
and doesn't actually apply those changes
until you call executeSaveRequest.
And, a couple of important things about saving.
Number one is that the save request can include multiple
changes, and when you execute it,
all of them will be applied during, um,
when it gets executed.
And the second is that the save request requires mutable
contacts, so you want to be careful not
to access these mutable contacts on another thread,
while a save is in process.
So now that you know how to fetch
and save a user's contacts, I'll invite Julien up on stage
to talk about using contacts in the user interface.
JULIEN ROBERT: Thank you, Dave.
I'm Julien and I'm an engineer in the iOS contacts team.
And now that Bruce and Dave made you experts
in the Contacts Framework, I will talk about user interface
and show you how to pick and display contacts in your app.
Coming along with Contacts Framework we have a new UI
Framework called contacts UI.
It is available on both iOS 9 and OS X El Capitan.
This provides you with two clusters, first the picker,
which displays a list of all the users contacts,
to let him selectively import contact information
into your app.
And secondly, the contact view controller,
which is used to display a contact.
In the rest of this presentation I will talk
about the iOS version of the classes,
but the OS X counterparts are pretty similar.
Let's talk about picking contact first.
The class you use for that is CNContact Picker
It is a direct replacement of the class we had
in Address Book UI, AB People Picker Navigation Controller.
As you can guess by its name, it is a direct subclass
of UA View Controller but you still must present it,
and not push it in a navigation controller.
It is always out of process.
It has the great advantage of not requiring the user
to let your app access its contacts.
So when you present a contact picker,
you will never see the dialogue that Bruce -- that Dave showed.
One thing that is important is
that the contact picker may return partial contacts.
For example, if you set a limited set
of displayed property keys, you will only get those keys
in the contact that you get back.
And the behavior of the picker is defined by two things,
first the delegate method that you implement, and second,
the predicate that you set on it.
And we are going to talk about those just after.
But last but not least the picker must
JULIEN ROBERT: Let's talk about the delegate method first.
So if your app is interested by a single contact,
and you want have this familiar look of the picker,
you simply need to implement the didSelectContact delegate
method, and you get a CNContact back.
So again, these contacts may be partial.
If you are interested in a single property,
you implement a did Select Contact Property delegate
method, and you get a CNContactProperty object.
So, this object is actually from the Contacts Framework
but we haven't seen it before, so let's take a look.
It is a simple wrapper class that contains the contact
that was selected, as well as the key of the property
that was selected by the user.
Its value and potentially, the identifier,
is the property, is labeled value.
But you may also be interested in having multiple contacts.
And you would get this appearance.
To do that is very simple.
You just implement the didSelectContact delegate
method, and you get as expected,
an array of sent contact objects.
This also works for properties, you can get multiple of them
by implementing the didSelectContactProperties
delegate method, and get an array of CNContact properties.
So now let's talk about predicates.
Predicates lets you customize the behavior of the panel
and we have three of them.
The first one is predicate for enabling contact.
This lets you decide which contacts are available
to the user and which are not.
If I take the example that we've seen earlier,
and if you want a user to only select members
of the Parker family, for example,
you would create a predicate where you want to match contacts
with the Parker family name.
You set it as a predicateForEnablingContact.
And once the picker is represented,
you can see that you can only select people
with the Parker family name.
The second one that we have is predicate ForSelectionOfContact.
This one is evaluated when the user will tap on the contact.
And if it evaluates to true,
then the contact is returned to your app.
Otherwise we will display the contact card.
Similarly for properties we have predicate
And if it evaluates to true, the property that is tapped
by the user will be returned to your app,
otherwise the default action will be performed,
such as making a phone call or creating a new e-mail.
One thing to note is that this last predicate is evaluated
on [the] CNContactProperty object,
whereas the first two are evaluated on CNContact objects.
I would like to point out that you need to be coherent
between the predicates you set
and the delegate methods that you implement.
For example, you should only implement the didSelectContact
delegate method, but set the predicate for selection
of property predicate, then, doesn't really make sense,
and you would see a log, and your predicate will be ignored.
Right, so now that you know how to pick contacts,
let's talk about viewing them in your app.
So we now have just one class
to replace the three classes what we had in Address Book UI.
But you can still get the behavior that you want
by using the appropriate creation method.
The first one is viewControllerForContact,
which would give you a view controller that is the same
as in contacts app, iPhone app.
If you want to create a new contact,
you can use viewControllerForNewContact,
and you get this View Controller which is always in editing mode.
And lastly, if you have a contact that is
from an unknown origin, such as a vCard, for example,
you use viewControllerForUnknownContact.
One thing we've added in iOS 9 is this update contact button
which will be displayed automatically
if there is already a contact
in the user's contact matching the name
of the contact you are displaying.
And if the user taps on it, it will display the UI
to update the existing contact with the new information.
This Contact View Controller is now always out of process,
and the reason for that is
that we may add some additional information
such as contacts data that was found in mail.
And as Dave pointed out, it is important
to fetch the contacts using the right keys.
So if you want to display it in the Contacts View Controller,
it must be fetched using the descriptorForRequiredKeys
of the Contacts View Controller.
So let's look at a quick code example on how
to display a contact from an identifier.
First you would fetch the contact
with the descriptorForRequiredKeys
of the Contact View Controller.
Then you create the Contact View Controller with forContact,
because we want a regular look at the Contact View Controller.
If you already have a contact store, you should set it
to the Contacts View Controller so that we can reuse it.
Set self as a delegate.
Push the View Controller.
And then in your delegate method you will get called
when the contact is modified.
Alright, so it is nice to look at a code sample,
but what is better is [to] build an app together,
let's do that now.
And the app we are going to build is called Meow.
And it's an app that lets you share your emotions
with your friends by sending them cat sounds.
So if I run the app, you can see at the top is a mood selector.
And then at the bottom is your friends list, which is empty
for now, and this is what we are going to build now.
The app is using an e-mail address to send the cat sounds.
So what we need is just a nickname and e-mail address.
So if I hit save, nothing happens
because it is not implemented yet.
So this is what we are going to do.
When I hit save, this addBuddy function is called,
and we will implement it now.
First we create a mutable contact
because we are going to modify it.
Then we set the nickname to be the value from the text field.
The emailAddresses property is set as an array
of a single label value.
We have the value being from the text field.
And finally we add this new contact to our list of contacts.
So let's run and see how it works now.
So I'm going to use prefilled values, and add Emily
to my friends, OK, my family.
You can notice this info button here.
And we want to show the contact view
when we click on this info button.
So this is what we are going to implement now.
So when I tap this button, the showContact function is called.
So let's fill it in.
First we create a Contact View Controller for the contact
that was, ah, that we want to show.
Then we set the contacts store to the one we already have.
And finally, we push the View Controller.
Let's just try, and okay, we can see the info for Emily.
Great. But what if we want to add a contact in our list,
that is already in the user's contacts?
So this is what we are going to do here.
And for that we are going to use the contact picker.
So this function is called when I tap on addFromContacts.
And I am going to implement it now.
First thing I'm doing is create the contact picker controller.
Then since we are only interested in e-mail addresses,
I limit the properties to e-mail addresses.
Then we want, ah, to, the user to select contacts who have only
at least one e-mail address.
We see this is the part of the predicate that is doing that.
And who are not already in our list of friends,
because we don't want duplicates.
Finally, is the user, is contact already,
[who] has exactly one e-mail address, we don't need
to push the [card?], We want it to be written directly.
This is what this predicate is doing.
We set ourself as a delegate and we present the View Controller.
We also need delegate methods where we add the new contact
to our list of contacts.
So it is straight now.
And if I select John Appleseed, I know he has two e-mails.
So the contact card is pushed.
I would select one e-mail, and we have John in our list.
If I add a new contact, first you can see
that now John Appleseed is unavailable
because he is already in my friends list.
But if I select David, he just has one e-mail address.
So the contact is returned directly.
So what happens if I want to show the card for John?
So we have an exception.
And the reason is that because we were not careful
when presenting the contact here,
because the contact picker returned the partial contacts,
it is missing some keys for the Contact View Controller.
So we are going to fix that by first checking
if the contact has the required keys to be used
in the Contact View Controller.
And if he does, we just use the code that we had before.
But if he does not, we will first ask the Store
to request access for contacts.
If the user grants access, we are going to have
to re-fetch the contact using its identifier.
And this time using the keysToFetch, the descriptor
for recorded keys of the CNContactViewController.
Then we call the same function again but this time
with our complete contacts ready to be used.
So let's try again.
So if I view the contact card for Emily,
we have no dialogue showing
up because Emily was created in code.
So she has all the fetch keys.
If I do the same on John, I re-fetch is necessary.
So at this point your app will access the user's contact.
So we say okay, and we can see all the contact information
So this concludes our demo.
Which makes me a bit sad.
So I will share my emotions with John.
(Sound of cat crying.)
JULIEN ROBERT: And I will call Bruce back
to conclude this presentation.
BRUCE STADNYK: Thank you, Dave and Julien
for showing us how to use contacts in our apps.
So you now have an Objective-C API to access contacts,
and it works well with Swift.
The Contacts API is the same across multiple Apple platforms.
Address book is being deprecated,
so start adopting now.
For more information you can refer to the contacts
in ContactsUI Framework References
on the developer library.
For technical support you can go to the Developer Forums,
and for general inquiries, Paul loves e-mail,
so you can e-mail him, and he's our app Frameworks evangelist.
Looking for something specific? Enter a topic above and jump straight to the good stuff.
An error occurred when submitting your query. Please check your Internet connection and try again.