Saltar al contenido

Contactos de iOS Cómo obtener un contacto por número de teléfono

Solución:

El problema con su implementación es que accede a la libreta de direcciones en cada búsqueda que realiza.

Si, en cambio, mantiene en memoria el contenido de la libreta de direcciones después del primer acceso, no alcanzará este alto uso de CPU.

  1. Primero mantenga una var perezosa en su controlador que contendrá el contenido de la libreta de direcciones:

    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. Iterar a través de la memoria array cuando busca un contacto con un número de teléfono específico:

    .

       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
    
    

Lo probé con una libreta de direcciones muy grande, funciona sin problemas.

Aquí está todo el controlador de vista parcheado como referencia.

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
    

Usé la respuesta de flohei para la parte de lazy var.

ACTUALIZACIÓN DE SWIFT 4

1) Agregar a .plist

NSContactsUsageDescription
Our application needs to your contacts

2) Solicite autorización si no la tiene

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) Verifique el estado de la autorización si lo solicita antes

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

    

3) Llamar a Obtener contactos

    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) ESTA ES LA FUNCIÓN PARA OBTENER EL NOMBRE DE CONTACTO O POR NÚMERO

    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 ""
    

Puntuaciones y comentarios

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada.