IOS Contacts How to get a contact by phone

I just want to get the contact name and surname by phone number. I tried this, but it is too slow, and the processor dials% 120.

let contactStore = CNContactStore() let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey] var contacts = [CNContact]() do { try contactStore.enumerateContactsWithFetchRequest(CNContactFetchRequest.init(keysToFetch: keys), usingBlock: { (contact, cursor) in if (!contact.phoneNumbers.isEmpty) { for phoneNumber in contact.phoneNumbers { if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber { do { let libPhone = try util.parseWithPhoneCarrierRegion(phoneNumberStruct.stringValue) let phoneToCompare = try util.getNationalSignificantNumber(libPhone) if formattedPhone == phoneToCompare { contacts.append(contact) } }catch { print(error) } } } } }) if contacts.count > 0 { contactName = (contacts.first?.givenName)! + " " + (contacts.first?.familyName)! print(contactName) completionHandler(contactName) } }catch { print(error) } 

Also, when I use the phonenumber Kit to find contacts with its growing processor and provide a later response.

 var result: [CNContact] = [] let nationalNumber = PhoneNumberKit().parseMultiple([phoneNumber]) let number = nationalNumber.first?.toNational() print(number) for contact in self.addressContacts { if (!contact.phoneNumbers.isEmpty) { let phoneNumberToCompareAgainst = number!.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") for phoneNumber in contact.phoneNumbers { if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber { let phoneNumberString = phoneNumberStruct.stringValue let nationalContactNumber = PhoneNumberKit().parseMultiple([phoneNumberString]) let nationalContactNumberString = nationalContactNumber.first?.toNational() if nationalContactNumberString == number { result.append(contact) } } } } } return result 
+10
source share
2 answers

The problem with your implementation is that you get access to the address book with every search you do.

If instead you store the contents of the address book after the first access, you will not achieve this high CPU utilization.

  • First, keep the lazy var in the controller, which will contain the contents of the address book:

     lazy var contacts: [CNContact] = { let contactStore = CNContactStore() let keysToFetch = [ CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey] // Get all the containers var allContainers: [CNContainer] = [] do { allContainers = try contactStore.containersMatchingPredicate(nil) } catch { print("Error fetching containers") } var results: [CNContact] = [] // Iterate all containers and append their contacts to our results array for container in allContainers { let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier) do { let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch) results.appendContentsOf(containerResults) } catch { print("Error fetching results for container") } } return results }() 
    1. Iterating through an array in memory when you look for a contact with a specific phone number:

.

  func searchForContactUsingPhoneNumber(phoneNumber: String) -> [CNContact] { var result: [CNContact] = [] for contact in self.contacts { if (!contact.phoneNumbers.isEmpty) { let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") for phoneNumber in contact.phoneNumbers { if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber { let phoneNumberString = phoneNumberStruct.stringValue let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") if phoneNumberToCompare == phoneNumberToCompareAgainst { result.append(contact) } } } } } return result } 

I tested it with a very large address book, it runs smoothly.

Here is the full view controller, fixed together for the link.

 import UIKit import Contacts class ViewController: UIViewController { lazy var contacts: [CNContact] = { let contactStore = CNContactStore() let keysToFetch = [ CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactEmailAddressesKey, CNContactPhoneNumbersKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey] // Get all the containers var allContainers: [CNContainer] = [] do { allContainers = try contactStore.containersMatchingPredicate(nil) } catch { print("Error fetching containers") } var results: [CNContact] = [] // Iterate all containers and append their contacts to our results array for container in allContainers { let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier) do { let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch) results.appendContentsOf(containerResults) } catch { print("Error fetching results for container") } } return results }() override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view, typically from a nib. let contact = searchForContactUsingPhoneNumber("(555)564-8583") print(contact) } override func didReceiveMemoryWarning() { super.didReceiveMemoryWarning() // Dispose of any resources that can be recreated. } func searchForContactUsingPhoneNumber(phoneNumber: String) -> [CNContact] { var result: [CNContact] = [] for contact in self.contacts { if (!contact.phoneNumbers.isEmpty) { let phoneNumberToCompareAgainst = phoneNumber.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") for phoneNumber in contact.phoneNumbers { if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber { let phoneNumberString = phoneNumberStruct.stringValue let phoneNumberToCompare = phoneNumberString.componentsSeparatedByCharactersInSet(NSCharacterSet.decimalDigitCharacterSet().invertedSet).joinWithSeparator("") if phoneNumberToCompare == phoneNumberToCompareAgainst { result.append(contact) } } } } } return result } } 

I used flohei answer for the lazy part of var.

+20
source

SWIFT 4 UPDATE

1) Add to .plist

 <key>NSContactsUsageDescription</key> <string>Our application needs to your contacts</string> 

2) Request authorization if you do not have one

 func requestAccess() { let store = CNContactStore() store.requestAccess(for: .contacts) { granted, error in guard granted else { DispatchQueue.main.async { self.presentSettingsActionSheet() } return } } } func presentSettingsActionSheet() { let alert = UIAlertController(title: "Permission to Contacts", message: "This app needs access to contacts in order to ...", preferredStyle: .actionSheet) alert.addAction(UIAlertAction(title: "Go to Settings", style: .default) { _ in let url = URL(string: UIApplicationOpenSettingsURLString)! UIApplication.shared.open(url) }) alert.addAction(UIAlertAction(title: "Cancel", style: .cancel)) present(alert, animated: true) } 

2) Check the authorization status if you request it earlier

  if CNContactStore.authorizationStatus(for: .contacts) == .authorized { getContacts() } 

3) Call Get contacts

  var contacts = [CNContact]() func getContacts(){ let contactStore = CNContactStore() let keys = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactPhoneNumbersKey, CNContactImageDataAvailableKey, CNContactThumbnailImageDataKey] let request = CNContactFetchRequest(keysToFetch: keys as [CNKeyDescriptor]) request.sortOrder = CNContactSortOrder.givenName do { try contactStore.enumerateContacts(with: request) { (contact, stop) in self.contacts.append(contact) } } catch { print("unable to fetch contacts") } } 

4) THIS IS THE FUNCTION OF OBTAINING A NAME OF CONTACT OR NUMBER

  func getNameFromContacts(number: String) -> String { var contactFetched : CNContact var contactName = "" if contacts.count > 0 { let numberToBeCompared = number.components(separatedBy:CharacterSet.decimalDigits.inverted).joined(separator: "") for c in contacts { for n in c.phoneNumbers { if let numberRetrived = n.value as? CNPhoneNumber { let numberRetrivedFixed = numberRetrived.stringValue.components(separatedBy:CharacterSet.decimalDigits.inverted).joined(separator: "") if numberRetrivedFixed.elementsEqual(numberToBeCompared){ contactName = c.givenName // OR get the contact --> c contactFetched = c } } } } return contactName } else { return "" } } 
+1
source

All Articles