In Today’s post I will show you How to do below things in Swift 2…
1. Show Contact Picker using System In-Built UI & Pick a Contact
2. Load all Contacts in a TableView
3. Search a Contact
4. Add a New Contact
5. Update a Contact
6. Delete a Contact
Before using the contacts we need to get permission from the User. For that we need to call some functions. I will write those functions in the AppDelegate method.
My AppDelegate will look like this.
import UIKit import ContactsUI import AddressBook @UIApplicationMain class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? let contactStore = CNContactStore() func showAlertMessage(message: String) { let alertController = UIAlertController(title: "Contacts Demo Swift", message: message, preferredStyle: UIAlertControllerStyle.Alert) let dismissAction = UIAlertAction(title: "OKAY", style: UIAlertActionStyle.Default) { (action) -> Void in } alertController.addAction(dismissAction) let pushedViewControllers = (self.window?.rootViewController as! UINavigationController).viewControllers let presentedViewController = pushedViewControllers[pushedViewControllers.count - 1] //Show the Alert presentedViewController.presentViewController(alertController, animated: true, completion: nil) } func requestForAccess(completionHandler: (accessGranted: Bool) -> Void) { let authorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts) switch authorizationStatus { case .Authorized: completionHandler(accessGranted: true) case .Denied, .NotDetermined: self.contactStore.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (access, accessError) -> Void in if access { completionHandler(accessGranted: access) } else { if authorizationStatus == CNAuthorizationStatus.Denied { dispatch_async(dispatch_get_main_queue(), { () -> Void in let message = "\(accessError!.localizedDescription)\n\nPlease allow the app to access your contacts through the Settings." self.showAlertMessage(message) }) } } }) default: completionHandler(accessGranted: false) } } }
1. Show Contact Picker using System In-Built UI & Pick a Contact
How to Do
You need to use an instance of the CNContactPickerViewController class inside the ContactsUI framework. It has two delegate methods.
func contactPickerDidCancel(picker: CNContactPickerViewController)
Gets called when the user cancels his request to pick a contact.contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact)
Gets called when the user picks a contact from the Contacts list.
CNContactPickerViewController cannot be pushed to the stack, they need to be presented modally.
So For showing the CNContactPickerViewController you need to do like this.
self.presentViewController(peoplePicker, animated: true, completion: nil)
I will show up the Contacts List using the Inbuild System UI.
Now we will implement “didSelectContact” delegate…
If the person has multiple contact numbers, then it will show an alert to select one..
func contactPicker(picker: CNContactPickerViewController, didSelectContact contact: CNContact) { self.statusLabel.hidden = true //Dismiss the picker VC picker.dismissViewControllerAnimated(true, completion: nil) //See if the contact has multiple phone numbers if contact.phoneNumbers.count > 1 { self.showContactView.hidden = false //If so we need the user to select which phone number we want them to use let multiplePhoneNumbersAlert = UIAlertController(title: "Which one?", message: "This contact has multiple phone numbers, which one did you want use?", preferredStyle: UIAlertControllerStyle.Alert) //Loop through all the phone numbers that we got back for number in contact.phoneNumbers { //Each object in the phone numbers array has a value property that is a CNPhoneNumber object, Make sure we can get that if let actualNumber = number.value as? CNPhoneNumber { //Get the label for the phone number var phoneNumberLabel = number.label //Strip off all the extra crap that comes through in that label phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) //Create a title for the action for the UIAlertVC that we display to the user to pick phone numbers let actionTitle = phoneNumberLabel + " - " + actualNumber.stringValue //Create the alert action let numberAction = UIAlertAction(title: actionTitle, style: UIAlertActionStyle.Default, handler: { (theAction) -> Void in //Create an empty string for the contacts name var nameToSave = "" //See if we can get A frist name if contact.givenName == "" { //If Not check for a last name if contact.familyName == "" { //If no last name set name to Unknown Name nameToSave = self.UNKNOWN_NAME }else{ nameToSave = contact.familyName } }else{ nameToSave = contact.givenName } // See if we can get image data if let imageData = contact.imageData { //If so create the image let userImage = UIImage(data: imageData) self.imgContact.image = userImage; } //Do what you need to do with your new contact information here! //Get the string value of the phone number like this: actualNumber.stringValue self.lblName.text = nameToSave; self.lblNumber.text = actualNumber.stringValue }) //Add the action to the AlertController multiplePhoneNumbersAlert.addAction(numberAction) } } //Add a cancel action let cancelAction = UIAlertAction(title: "Cancel", style: UIAlertActionStyle.Cancel, handler: { (theAction) -> Void in //Cancel action completion print("User Cancelled") }) //Add the cancel action multiplePhoneNumbersAlert.addAction(cancelAction) //Present the ALert controller self.presentViewController(multiplePhoneNumbersAlert, animated: true, completion: nil) }else{ //Make sure we have at least one phone number if contact.phoneNumbers.count > 0 { self.showContactView.hidden = false //If so get the CNPhoneNumber object from the first item in the array of phone numbers if let actualNumber = contact.phoneNumbers.first?.value as? CNPhoneNumber { //Get the label of the phone number var phoneNumberLabel = contact.phoneNumbers.first!.label //Strip out the stuff you don't need phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("_", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("$", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("!", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString("<", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) phoneNumberLabel = phoneNumberLabel.stringByReplacingOccurrencesOfString(">", withString: "", options: NSStringCompareOptions.LiteralSearch, range: nil) //Create an empty string for the contacts name var nameToSave = "" //See if we can get A frist name if contact.givenName == "" { //If Not check for a last name if contact.familyName == "" { //If no last name set name to Unknown Name nameToSave = UNKNOWN_NAME }else{ nameToSave = contact.familyName } }else{ nameToSave = contact.givenName } self.lblName.text = nameToSave // See if we can get image data if let imageData = contact.imageData { //If so create the image let userImage = UIImage(data: imageData) self.imgContact.image = userImage; } //Do what you need to do with your new contact information here! //Get the string value of the phone number like this: print(actualNumber.stringValue) self.lblNumber.text = actualNumber.stringValue } }else{ self.statusLabel.hidden = false; self.statusLabel.text = NO_PHONE_NUMBERS } } }
contactPickerDidCancel Delegate..
func contactPickerDidCancel(picker: CNContactPickerViewController) { picker.dismissViewControllerAnimated(true, completion: nil) }
2. Load all contacts from the System Contacts.
I am assuming that you will have a Tableview with Custom Cell for displaying a Contact Name and Thumbnail image of the contact.
The below function will fetch all the contacts.
func fetchContacts() { dataArray = NSMutableArray() let toFetch = [CNContactGivenNameKey, CNContactImageDataKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey] let request = CNContactFetchRequest(keysToFetch: toFetch) do{ try appDelegate.contactStore.enumerateContactsWithFetchRequest(request) { contact, stop in print(contact.givenName) print(contact.familyName) print(contact.identifier) var userImage : UIImage; // See if we can get image data if let imageData = contact.imageData { //If so create the image userImage = UIImage(data: imageData)! }else{ userImage = UIImage(named: "no_contact_image")! } let data = Data(name: contact.givenName, image: userImage) self.dataArray?.addObject(data) } } catch let err{ print(err) self.errorStatus() } self.tableView.reloadData() }
3. Search a Contact.
There are actually three different methods for searching contacts.
1. unifiedContactsMatchingPredicate(_:keysToFetch:) method of CNContactStore
This allows you to fetch all contacts that match a certain predicate.2. enumerateContactsWithFetchRequest(_:usingBlock:) method of CNContactStore
This allows you to enumerate through all contacts that match a fetch request.
The fetch request can have a predicate if you want it to.
Otherwise, you can use this method with a request object that does not have a predicate, in order to fetch all contacts.3. unifiedContactWithIdentifier(_:keysToFetch:) method of CNContactStore
This fetches only a single contact with a given identifier, if it can find one.
Use this method to fetch properties for a partially fetched contact.
Code
func findInContacts() { dataArray = NSMutableArray() let searchKey = "coderzheaven" var toFetch = [CNContactGivenNameKey, CNContactImageDataKey, CNContactFamilyNameKey, CNContactImageDataAvailableKey] let predicate = CNContact.predicateForContactsMatchingName(searchKey) do{ let contacts = try appDelegate.contactStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: toFetch) for contact in contacts{ /* guard contact.imageDataAvailable else{ continue } */ if contact.isKeyAvailable(CNContactImageDataKey){ var userImage : UIImage; // See if we can get image data if let imageData = contact.imageData { //If so create the image userImage = UIImage(data: imageData)! }else{ userImage = UIImage(named: "no_contact_image")! } let data = Data(name: contact.givenName, image: userImage) self.dataArray?.addObject(data) } else { toFetch += [CNContactImageDataKey, CNContactGivenNameKey] do{ let contact = try appDelegate.contactStore.unifiedContactWithIdentifier( contact.identifier, keysToFetch: toFetch) print(contact.givenName) print(contact.identifier) } catch let err{ print(err) } } } self.tableView.reloadData() } catch let err{ print(err) } }
4. Add a New Contact..
We have to do the following things to add a contact
- Request access from the user for accessing Contacts.
- Create an instance of the CNMutableContact class.
- Set the properties we want to fetch from the Contacts Database like given name, email address etc.
- Instantiate CNSaveRequest, call the addContact(_:toContainerWithIdentifier:) method on it, and pass your contact to it. Set the container ID to nil.
Once you have the request, execute it on your store instance using executeSaveRequest(_:).
The below fuction will add a contact to the Contacts Database.
func createContact() { let fooBar = CNMutableContact() fooBar.givenName = "Coderz" fooBar.middleName = "Heaven" fooBar.familyName = "Coderz" fooBar.nickname = "Coderz" //profile photo if let img = UIImage(named: "no_contact_image"), let data = UIImagePNGRepresentation(img){ fooBar.imageData = data } //set the phone numbers let homePhone = CNLabeledValue(label: CNLabelHome, value: CNPhoneNumber(stringValue: "1234567")) let workPhone = CNLabeledValue(label: CNLabelWork, value: CNPhoneNumber(stringValue: "9876543")) fooBar.phoneNumbers = [homePhone, workPhone] //set the email addresses let homeEmail = CNLabeledValue(label: CNLabelHome, value: "coderzheaven@gmail.com") let workEmail = CNLabeledValue(label: CNLabelWork, value: "coderzheaven@gmail.com") fooBar.emailAddresses = [homeEmail, workEmail] //job info fooBar.jobTitle = "Software Developer" fooBar.organizationName = "CoderzHeaven" fooBar.departmentName = "IT" //social media let facebookProfile = CNLabeledValue(label: "FaceBook", value: CNSocialProfile(urlString: nil, username: "CoderzHeaven", userIdentifier: nil, service: CNSocialProfileServiceFacebook)) let twitterProfile = CNLabeledValue(label: "Twitter", value: CNSocialProfile(urlString: nil, username: "coderzheaven", userIdentifier: nil, service: CNSocialProfileServiceTwitter)) fooBar.socialProfiles = [facebookProfile, twitterProfile] //instant messaging let skypeAddress = CNLabeledValue(label: "Skype", value: CNInstantMessageAddress(username: "coderzheaven", service: CNInstantMessageServiceSkype)) fooBar.instantMessageAddresses = [skypeAddress] //some additional notes fooBar.note = "Heaven of all working codes." //birthday let birthday = NSDateComponents() birthday.year = 1987 birthday.month = 9 birthday.day = 27 fooBar.birthday = birthday //finally save let request = CNSaveRequest() request.addContact(fooBar, toContainerWithIdentifier: nil) do{ try appDelegate.contactStore.executeSaveRequest(request) print("Successfully added the contact") self.statusLabel.text = ("Successfully added the contact \n\(fooBar.givenName)") } catch let err{ print("Failed to save the contact. \(err)") self.statusLabel.text = ("Failed to add the contact") } }
5. Update a Contact.
How to do?
- Call the mutableCopy() method of your CNContact class will give you an instance of the CNMutableContact
- Change properties as you would with a contact of type CNContact.
- Instantiate CNSaveRequest, call the updateContact(_:) method on it, and pass your mutable contact to that method.
Code
func updateContact() { let predicate = CNContact.predicateForContactsMatchingName("coderzheaven") let toFetch = [CNContactGivenNameKey] do{ let contacts = try appDelegate.contactStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: toFetch) guard contacts.count > 0 else{ print("No contacts found") return } //only do this to the first contact matching our criteria guard let contact = contacts.first else{ return } let newName = "CoderzHeaven New" let newContact = contact.mutableCopy() as! CNMutableContact //set new name newContact.givenName = newName let req = CNSaveRequest() req.updateContact(newContact) /** To add new email address let emailAddress = CNLabeledValue(label: CNLabelWork, value: "newemail@email.com") newContact.emailAddresses.append(emailAddress) **/ try appDelegate.contactStore.executeSaveRequest(req) print("Successfully edited") self.statusLabel.hidden = false self.statusLabel.text = "Successfully Updated coderzheaven" } catch let err{ print(err) self.errorStatus() } }
6. Delete a Contact
How to ?
- Find the Contact to delete using the methods mentioned in the Search Contact Section
- Instantiate an object of type CNSaveRequest.
- Issue the deleteContact(_:) function on the request and pass your mutable contact to it.
- Execute your request using the executeSaveRequest(_:) method of your contact store.
Code
func deleteContact() { let predicate = CNContact.predicateForContactsMatchingName("coderzheaven") let toFetch = [CNContactEmailAddressesKey] do{ let contacts = try appDelegate.contactStore.unifiedContactsMatchingPredicate(predicate, keysToFetch: toFetch) guard contacts.count > 0 else{ print("No contacts found") return } //only do this to the first contact matching our criteria guard let contact = contacts.first else{ return } let req = CNSaveRequest() let mutableContact = contact.mutableCopy() as! CNMutableContact req.deleteContact(mutableContact) do{ try appDelegate.contactStore.executeSaveRequest(req) print("Successfully deleted the Contact") self.statusLabel.text = "Successfully Deleted coderzheaven" } catch let e{ print("Error = \(e)") } } catch let err{ print(err) self.errorStatus() } }
You can download the complete Source Code from here.