Formatting Contact Data - Contacts - iOS 9 Swift Programming Cookbook (2015)

iOS 9 Swift Programming Cookbook (2015)

Chapter 4. Contacts

4.5 Formatting Contact Data

Problem

You want to present local contacts’ name and postal address in a localized and readable way, regardless of the current language on the user’s device.

Solution

Use an instance of the CNContactFormatter or the CNPostalAddressFormatter classes. The former one can easily be used to format the contact’s name, and the latter is self-explanatory.

Discussion

The CNContactFormatter class allows you to format the name of any contact, according to the localization settings of the current device. For instance, in some languages, the last name of a person may be mentioned first. You can use the stringFromContact(_:) function of this method to get the full name.

NOTE

You must fetch the full name of a contact from the store for this method to work at all. Otherwise, you might get an exception.

Since we have already talked about Recipe 4.2, I have written a simple extension on CNContactStore that allows me to fetch the first contact that it finds with a given name. I’ve named this method firstUnifiedContactMatchingName(_:toFetch:output:) and it calls my output block when it finds the contact or if an error occurs. You don’t have to know the full implementation of this method because you already know how you can fetch a contact with a given name.

So let’s look at an example where we fetch a contact from the store and print his full name to the console:

let toFetch =

CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)

store.firstUnifiedContactMatchingName("john", toFetch: [toFetch]){

guard let contact = $0 else{

return

}

guard let name = CNContactFormatter().stringFromContact(contact) else{

return

}

print("The name of the contact is \(name)")

}

Note that I am using the descriptorForRequiredKeysForStyle(_:) class method of the CNContactFormatter class to get an object of type CNKeyDescriptor and then pass the results to firstUnifiedContactMatchingName(_:toFetch:output:) when fetching the contact. The aforementioned method on CNContactFormatter tells the system what properties of the contact to fetch; in this case, all the properties that are required for the full name, including the first, middle, and last names.

Now imagine that we want to find a contact’s localized phonetic name. A phonetic name is the name of a person, written as it is pronounced, rather than how the name is spelled. For instance, a person’s name might be Julian, but in Swedish, because the J is pronounced as in “you”, this name will eventually be pronounced as “you-lian”. So “you-lian” is the phonetic equivalent of the name “Julian” in Swedish. These phonetic names are very useful for Siri. So a Swedish speaker will ask Siri to phone up “you-lian” and Siri will have no idea who that is unless the phonetic name has been set for that user.

Create a contact in your list. Set his first name to “Julian” and last name to “Julianson”. Then tap on the “add field” button at the bottom of the create-contact screen and add the phonetic first and last name fields to the contact (see Figure 4-5).

Figure 4-5. Add the phonetic first name and last name fields to your new contact

Set the phonetic first name to “Youlian” and the phonetic last name to “Youlianson” until your contact looks like Figure 4-6.

Figure 4-6. Your contact’s phonetic name is also displayed, if set

Let’s now look at an example where we fetch the phonetic name of a contact and then format it according to the localization on the current device. First, we need to find the fields in the contact store for phonetic name. We do that using the descriptorForRequiredKeysForStyle(_:)class method of CNContactFormatter and this time pass the value of PhoneticFullName to it. Because the stringFromContact(_:) class method of the CNContactFormatter class by default reads the full name, and not the phonetic full name, we will have to start using thestringFromContact(_:style:) instance method of this class instead. The last parameter to this function allows us to pass a style of type CNContactFormatterStyle that can be set to FullName or PhoneticFullName.

let style = CNContactFormatterStyle.PhoneticFullName

let toFetch =

CNContactFormatter.descriptorForRequiredKeysForStyle(style)

store.firstUnifiedContactMatchingName("julian", toFetch: [toFetch]){

guard let contact = $0 else{

return

}

guard let name = CNContactFormatter

.stringFromContact(contact, style: style) else{

return

}

print("The phonetic name of the contact is \(name)")

}

Aside from getting the localized full name of a contact, you can also get her address information, again, properly localized, using the CNPostalAddressFormatter class. Follow these steps:

1. Fetch your contact and make sure you include the CNContactPostalAddressesKey key.

2. Get the address from the contact using the postalAddresses property of CNContact. This will give you a value of type CNLabeledValue. Get the value of this labeled value and cast it to CNPostalAddress.

3. Instantiate CNPostalAddressFormatter.

4. Pass the postal address to the stringFromPostalAddress(_:) method of your postal address formatter to get the formatted address.

let toFetch = [CNContactPostalAddressesKey]

store.firstUnifiedContactMatchingName("john", toFetch: toFetch){

guard let contact = $0 else{

return

}

guard let firstAddress = contact.postalAddresses.first else{

print("no postal address could be found")

return

}

guard let address = firstAddress.value as? CNPostalAddress

where firstAddress.value is CNPostalAddress else{

return

}

let formatter = CNPostalAddressFormatter()

let formattedAddress = formatter.stringFromPostalAddress(address)

print("The address is \(formattedAddress)")

}

See Also