Show Menu

Expanding your company? Need a developer?

Submit your 30 day Job Listing for FREE

swift 2 contacts framework

In this Swift 2 Contacts Framework Tutorial I am going to be building up on the first part and showing you how to Search for Contacts, Update Contacts & Delete Contacts. This tutorial is for people who are wondering how to make an app that accesses the Swift 2 Contact Framework.

This tutorial is part of the Swift 2 Contacts Framework Tutorial series. If you are looking for how to make an app that utilities this framework then it is recommended that you read the first part of this series before proceeding:

All good? Great let’s get straight in to it.

Searching for Contacts

There are various methods for fetching contacts from CNContactStore. These are: enumerateContactsWithFetchRequest(_:usingBlock:), unifiedContactsMatchingPredicate(_:keysToFetch:) & unifiedContactWithIdentifier(_:keysToFetch:) . The first one, if you can guess from the name will allow you to enumerate through the contacts that match the fetch request. Now with this method, if you want to fetch all results you can use a method with a request object that does not have a predicate. The second one will allow you to simple fetch all the requests that match a specific predicate and the third one will fetch only a single contact with a given identifier (If there is one to return).

Find Specific Contact

let us assume that you want to find a contact in our address book with the name of “Sam”. We would start by creating a predicate using the class method predicateForContactsMatchingName:


let predicate = CNContact.predicateForContactsMatchingName("Sam")

Great, now we need to tell our application that if we find a result, we want to get the first and last name:


let toFetch = [CNContactGivenNameKey, CNContactFamilyNameKey]

Ok, now we’re going to use the unifiedContactsMatchingPredicate(_:keysToFetch:) method to fetch all the results that contain out predicate. It will go through all the matching results and print out their First and Last name along with the identifier property. Every object has an Identifier which looks like a UUID. Yes, you can fetch a contact an item by the identifier, I will show you how to do that later, back to this method.

I would be a good idea to wrap the following code in NSOperationQueue().addOperationWithBlock(_:) to make sure that your search will use the background thread:


do{
  let contacts = try store.unifiedContactsMatchingPredicate(
    predicate, keysToFetch: toFetch)

  for contact in contacts{
    print(contact.givenName)
    print(contact.familyName)
    print(contact.identifier)
  }
} catch let err{
   print(err)
}

Now we’re going to mix two methods together to get the same result. We will use the CNContactFetchRequest class & enumerateContactsWithFetchRequest(_:usingBlock:) method from CNContactStore.

We do this by first specifying what properties in the contacts we are interested in getting access to and then create the fetch request using the properties:


let toFetch = [CNContactGivenNameKey, CNContactFamilyNameKey]
let request = CNContactFetchRequest(keysToFetch: toFetch)

This will fetch the contacts from the method we mentioned before:


do{
  try store.enumerateContactsWithFetchRequest(request) {
    contact, stop in
    print(contact.givenName)
    print(contact.familyName)
    print(contact.identifier)
  }
} catch let err{
    print(err)
}

The block which is passed over to this method has two parameters, The first one is Contact and the second is Pointer (of type: Boolean). We use this Swift Enum to stop like so:


stop.memory = true

Ok, Let us try now with a different example. Lets say that you want to make an app that will fetch all results that are Similar to “Sam” And who have a photo attached to their contact profile. We go about this a different way, the way I will show you will first check that the contact has a photo and then check for the name. The following code will need to be wrapped in a Swift Do Catch Block

First we need to define our keys:


var toFetch = [CNContactImageDataAvailableKey]

Then, define your predicate:


let predicate = CNContact.predicateForContactsMatchingName("Sam")

Now. lets find all the contacts that match our predicate:


let contacts = try store.unifiedContactsMatchingPredicate(predicate, keysToFetch: toFetch)

Now that you have managed to get your contacts, you will now need to go through them and only get the ones that have the photos attached. First lets create a for statement that will allow us to loop through:


for contact in contacts{
}

Inside this statement we are going to use the Swift Guard syntax:


guard contact.imageDataAvailable else{
   continue
}

Inside the CNContact class there is a method called: isKeyAvailable(_:) which will return either a true or false value. We pass into this the CNContactImageDataKey to make the query. If the contact does have an image, we are going to print it out. To avoid errors we will wrap this in an If-Else Statement


//have we fetched image data?
if contact.isKeyAvailable(CNContactImageDataKey){
   print(contact.givenName)
   print(contact.identifier)
   print(UIImage(data: contact.imageData!))
} else {
// Failed Block
}

The else part of this statement will display something if the condition is not met. So, if there is no contacts with pictures then it will skip past the if part of the code and execute the else part. WE will use the identifier in this else section to get the contacts that do not. We will use the identifier to re fetch them:


else {
   toFetch += [CNContactImageDataKey, CNContactGivenNameKey]
   do{
     let contact = try store.unifiedContactWithIdentifier(
     contact.identifier, keysToFetch: toFetch)
     print(contact.givenName)
     print(UIImage(data: contact.imageData!))
     print(contact.identifier)
   } catch let err{
      print(err)
   }
}

Finally, let me show you the third option I presented earlier unifiedContactWithIdentifier(_:keysToFetch:). So, lets say that you have the identifier somewhere in your app that you can access, This is how you fetch a specific contact contact:



NSOperationQueue().addOperationWithBlock{[unowned store] in
    let id = "AGTH9B0T-2BTR-4A46-123A-3G1234W6FE0A:ABPerson"
    let toFetch = [CNContactGivenNameKey, CNContactFamilyNameKey]

    do{
      let contact = try store.unifiedContactWithIdentifier(id,
      keysToFetch: toFetch)
      print(contact.givenName)
      print(contact.familyName)
      print(contact.identifier)
    } catch let err{
       print(err)
    }
}

Updating Contacts

Above I showed you three ways of how to search for a contact in Swift 2 Contact Framework. We’re going to be using the predicateForContactsMatchingName method to find a specific contact to update the email for that contact.

This will be the default contacts view in the simulator, I’m viewing this in the iPad simulator so my image might look slightly different than yours if you are viewing it in the iPhone Simulator.

swift 2 contacts framework tutorial

As you can see by the image above there is a contact called John Appleseed. Using the search contacts method mentioned above create your query for the predicate John like so:


let predicate = CNContact.predicateForContactsMatchingName("john")

What we are going to do, is run this script on the first contact that we find. We will also use the Swift Guard syntax:


guard contacts.count > 0 else{
    print("No contacts found matching your predicate")
    return
}

Now we need to declare the email that we are going to use:


let newEmailAdd = "[email protected]"

But what is he already has this email stored? We can use a Swift if-statement to check that, If he does have the email stored already for this contact then we will just exit the execution of this code, if not, we will carry on with the script:


for email in contact.emailAddresses{
    if email.value as! String == newEmailAdd {
        print("This contact already has this email")
        return
     }
}

Now that we have performed this check, we can run the code that will insert into the contacts store. We first create an instance of CNMutableContact and create a constant of type CNLabeledValue which we then append together:


let john = contact.mutableCopy() as! CNMutableContact
let emailAddress = CNLabeledValue(label: CNLabelWork, value: "[email protected]")
        
john.emailAddresses.append(emailAddress)

Now, lets get it all saved:


let req = CNSaveRequest()
req.updateContact(john)
try store.executeSaveRequest(req)
print("Successfully added the email")

You can save multiple entries at the same time with this method also. See the official apple documentation: CNSaveRequest

Now, run your app and see the result.

Congratulations, you have just updated a contact in the iOS Contact framework.

Delete Contact

The iOS contacts framework gives us the function deleteContact(_:) to help us delete contacts. Hopefully you’ve understood this tutorial enough so far to proceed as I’m only going to outline the process and let you have a try. Just like we have throughout this tutorial we are going to instantiate an object of type CNSaveRequest, Issue the deleteContact(_:) function that I just mentioned and pass the mutable contact to it. Then, Like when we created contacts or updated contacts we are going to use the executeSaveRequest(_:).

Please note that Delete means Delete! Contacts that are deleted can not be obtained again. This shouldn’t matter too much on the simulator but you do need to make sure that you have safety protocols in place so that you don’t delete a users contacts.

So, Did you manage to get the delete working? Ok, Fine, I will post the full code so you can see.


let predicate = CNContact.predicateForContactsMatchingName("John")
let toFetch = [CNContactEmailAddressesKey]

do{
  let contacts = try store.unifiedContactsMatchingPredicate(predicate,keysToFetch: toFetch)
  guard contacts.count > 0 else{
    print("No contacts found")
    return
  }
 
  guard let contact = contacts.first else{
    return
  }

  let req = CNSaveRequest()
  let mutableContact = contact.mutableCopy() as! CNMutableContact
  req.deleteContact(mutableContact)

  do{
    try store.executeSaveRequest(req)
    print("Success, You deleted the user")
  } catch let e{
    print("Error = \(e)")
  }
} catch let err{
   print(err)
}

Summary

In this Swift Contact Framework tutorial I have shown you how to search for contacts in the iOS Contact framework using three methods: enumerateContactsWithFetchRequest(_:usingBlock:), unifiedContactsMatchingPredicate(_:keysToFetch:) & unifiedContactWithIdentifier(_:keysToFetch:). Using these techniques, I have shown you how to delete contacts using deleteContact(_:)

Part 3

I’m currently writing part three which will cove:; Formatting Data and using the Prebuilt UI – Sign up to the mailing list to make sure you don’t miss out.

having issues?

We have a Questions and Answer section where you can ask your iOS Development questions to thousands of iOS Developers.

Ask Question

FREE Download!

Get your FREE Swift 2 Cheat Sheet and quick reference guide PDF download when you sign up to SwiftMonthly


Sharing is caring

If you enjoyed this tutorial, please help us and others by sharing using one of the social media buttons below.


Written by:

I work in the shadows. You can thank me by being a good soul.

Comments

comments