iOS联系人如何通过电话号码获取联系人

时间:2016-08-19 14:29:04

标签: ios swift ios9 contacts

我只想通过电话号码联系姓名和姓氏。我试过这个,但这太慢了,cpu超过了%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)
            }

当我使用phonenumber Kit查找联系人时,它会增加cpu并给出迟到的响应。

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

3 个答案:

答案 0 :(得分:21)

您的实施问题是您在每次搜索时都会访问地址簿。

如果您在第一次访问后将保留内存中的地址簿内容,则不会达到此高CPU使用率。

  1. 首先在控制器中保存一个lazy var,它将保存地址簿内容:

    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. 当您要查找具有特定电话号码的联系人时,请浏览内存中阵列:
    2.    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
      }
      

      我用一本非常大的地址簿测试了它,它运行顺畅。

      这是整个视图控制器拼凑在一起以供参考。

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

      我使用flohei's answer作为懒惰的var部分。

答案 1 :(得分:3)

必须为 Swift 5 进行这些更改:


lazy var contacts = {
            let contactStore = CNContactStore()
            let keysToFetch: [CNKeyDescriptor] = [
                CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
                CNContactEmailAddressesKey as CNKeyDescriptor,
                CNContactPhoneNumbersKey as CNKeyDescriptor,
                CNContactImageDataAvailableKey as CNKeyDescriptor,
                CNContactThumbnailImageDataKey as CNKeyDescriptor]

            // Get all the containers
            var allContainers: [CNContainer] = []
            do {
                allContainers = try contactStore.containers(matching: 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.predicateForContactsInContainer(withIdentifier: container.identifier)

                do {
                    let containerResults = try     contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch)
                    results.append(contentsOf: containerResults)
                } catch {
                    print("Error fetching results for container")
                }
            }

            return results
        }()

对于迭代和发现:

    func searchForContactUsingPhoneNumber(phoneNumber: String) -> [CNContact] {
         var result: [CNContact] = []

         for contact in contacts {
             if (!contact.phoneNumbers.isEmpty) {
                let phoneNumberToCompareAgainst = phoneNumber.components(separatedBy: NSCharacterSet.decimalDigits.inverted).joined(separator: "")
                 for phoneNumber in contact.phoneNumbers {
                     if let phoneNumberStruct = phoneNumber.value as? CNPhoneNumber {
                         let phoneNumberString = phoneNumberStruct.stringValue
                        let phoneNumberToCompare = phoneNumberString.components(separatedBy: NSCharacterSet.decimalDigits.inverted).joined(separator: "")
                         if phoneNumberToCompare == phoneNumberToCompareAgainst {
                             result.append(contact)
                         }
                     }
                 }
              }
         }

         return result
    }

答案 2 :(得分:1)

SWIFT 4更新

1)添加到.plist

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

2)如果您没有授权,请请求

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)如果您之前要求过授权状态,请检查

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

    }

3)呼叫获取联系人

    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)这是获取联系人姓名或电话号码的功能

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