【问题标题】:Fetching all contacts in ios Swift?在 ios Swift 中获取所有联系人?
【发布时间】:2016-03-02 14:40:35
【问题描述】:

我知道 ios swift 有一个 Contacts Framework,我可以在其中获取联系人,但我找不到任何方法来同时获取所有联系人,我可以从该数组中访问每个联系人。所有获取联系人的方法似乎都需要某种条件。有什么方法可以把所有的联系人放在一起吗?

谢谢

【问题讨论】:

  • @Ollie OP 正在寻找“联系人框架”的解决方案,而您发布的链接仍然是 ABAddressBook,我认为这没有帮助。
  • @Christopher 该问题的许多解决方案实际上都使用了联系人框架。第二个答案给出了详细的解释。

标签: ios swift cncontact


【解决方案1】:

Swift 4 和 5。我已经创建了 PhoneContacts 类。请将 NSContactsUsageDescription 键添加到您的 info.plist 文件中

 import Foundation
 import ContactsUI

class PhoneContacts {

    class func getContacts(filter: ContactsFilter = .none) -> [CNContact] { //  ContactsFilter is Enum find it below

        let contactStore = CNContactStore()
        let keysToFetch = [
            CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
            CNContactPhoneNumbersKey,
            CNContactEmailAddressesKey,
            CNContactThumbnailImageDataKey] as [Any]

        var allContainers: [CNContainer] = []
        do {
            allContainers = try contactStore.containers(matching: nil)
        } catch {
            print("Error fetching containers")
        }

        var results: [CNContact] = []

        for container in allContainers {
            let fetchPredicate = CNContact.predicateForContactsInContainer(withIdentifier: container.identifier)

            do {
                let containerResults = try contactStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keysToFetch as! [CNKeyDescriptor])
                results.append(contentsOf: containerResults)
            } catch {
                print("Error fetching containers")
            }
        }
        return results
    }
}

在另一个类中调用上述方法

import ContactsUI
func phoneNumberWithContryCode() -> [String] {

    let contacts = PhoneContacts.getContacts() // here calling the getContacts methods
    var arrPhoneNumbers = [String]()
    for contact in contacts {
        for ContctNumVar: CNLabeledValue in contact.phoneNumbers {
            if let fulMobNumVar  = ContctNumVar.value as? CNPhoneNumber {
                //let countryCode = fulMobNumVar.value(forKey: "countryCode") get country code
                   if let MccNamVar = fulMobNumVar.value(forKey: "digits") as? String {
                        arrPhoneNumbers.append(MccNamVar)
                }
            }
        }
    }
    return arrPhoneNumbers // here array has all contact numbers.
}

现在,获取联系人的电子邮件和电话

    enum ContactsFilter {
        case none
        case mail
        case message
    }

    var phoneContacts = [PhoneContact]() // array of PhoneContact(It is model find it below) 
    var filter: ContactsFilter = .none

    self.loadContacts(filter: filter) // Calling loadContacts methods

       fileprivate func loadContacts(filter: ContactsFilter) {
            phoneContacts.removeAll()
            var allContacts = [PhoneContact]()
            for contact in PhoneContacts.getContacts(filter: filter) {
                allContacts.append(PhoneContact(contact: contact))
            }

            var filterdArray = [PhoneContact]()
            if self.filter == .mail {
                filterdArray = allContacts.filter({ $0.email.count > 0 }) // getting all email 
            } else if self.filter == .message {
                filterdArray = allContacts.filter({ $0.phoneNumber.count > 0 })
            } else {
                filterdArray = allContacts
            }
            phoneContacts.append(contentsOf: filterdArray)

  for contact in phoneContacts {
      print("Name -> \(contact.name)")
      print("Email -> \(contact.email)")
      print("Phone Number -> \(contact.phoneNumber)")
    }
    let arrayCode  = self.phoneNumberWithContryCode()
    for codes in arrayCode {
      print(codes)
    }
     DispatchQueue.main.async {
       self.tableView.reloadData() // update your tableView having phoneContacts array
              }
            }
        }

PhoneContact 模型类

import Foundation
import ContactsUI

class PhoneContact: NSObject {

    var name: String?
    var avatarData: Data?
    var phoneNumber: [String] = [String]()
    var email: [String] = [String]()
    var isSelected: Bool = false
    var isInvited = false

    init(contact: CNContact) {
        name        = contact.givenName + " " + contact.familyName
        avatarData  = contact.thumbnailImageData
        for phone in contact.phoneNumbers {
            phoneNumber.append(phone.value.stringValue)
        }
        for mail in contact.emailAddresses {
            email.append(mail.value as String)
        }
    }

    override init() {
        super.init()
    }
}

【讨论】:

  • 对于“如果让 fulMobNumVar = ContctNumVar.value as?CNPhoneNumber”,我遇到“从 'CNPhoneNumber' 到 'CNPhoneNumber' 的条件转换总是成功”
【解决方案2】:

Contact Framework 问题的许多答案都建议对各种容器(帐户)进行迭代。但是,Apple 的文档将“统一联系人”描述为

代表同一个人的不同帐户中的联系人可能会自动链接在一起。链接的联系人在 OS X 和 iOS 应用程序中显示为统一联系人。统一联系人是合并到一个联系人中的一组链接联系人的内存中临时视图。

默认情况下,联系人框架返回统一联系人。每个获取的统一联系人 (CNContact) 对象都有自己的唯一标识符,该标识符不同于链接联系人集中任何单个联系人的标识符。应使用其标识符重新获取统一联系人。 Source

在单个数组中获取(部分,基于键)联系人列表的最简单方法如下:

      var contacts = [CNContact]()
    let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
    let request = CNContactFetchRequest(keysToFetch: keys)
    
    let contactStore = CNContactStore()
    do {
        try contactStore.enumerateContacts(with: request) {
            (contact, stop) in
            // Array containing all unified contacts from everywhere
            contacts.append(contact)
        }
    }
    catch {
        print("unable to fetch contacts")
    }

【讨论】:

  • 非常有帮助。如果我想获取姓名和号码,如果用户有多个号码如何解决这种情况
  • CNContact 返回 CNPhoneNumbers 数组。您可以简单地获取数组中的第一个数字,或者遍历列表并解析电话号码的 CNLabeledValues 以找到您想要的数字,例如“工作”或“移动”
  • self.contactStore 来自哪里?
  • @uzu 应该定义为contactStore = CNContactStore() 并且self.contactStore.enumerateContactsWithFetchRequest(request) 应该更改为self.contactStore.enumerateContacts(with: request)。
【解决方案3】:

Swift 4 更新

let contactStore = CNContactStore()
var contacts = [CNContact]()
let keys = [
        CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
                CNContactPhoneNumbersKey,
                CNContactEmailAddressesKey
        ] as [Any]
let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
do {
    try contactStore.enumerateContacts(with: request){
            (contact, stop) in
        // Array containing all unified contacts from everywhere
        contacts.append(contact)
        for phoneNumber in contact.phoneNumbers {
            if let number = phoneNumber.value as? CNPhoneNumber, let label = phoneNumber.label {
                let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
                print("\(contact.givenName) \(contact.familyName) tel:\(localizedLabel) -- \(number.stringValue), email: \(contact.emailAddresses)")
            }
        }
    }
    print(contacts)
} catch {
    print("unable to fetch contacts")
}

【讨论】:

  • 在添加此代码之前,在.Plist 中添加权限请求,键:Privacy - Contacts Usage Description 和值:Application wants to access your contacts list. ...
【解决方案4】:
    // You may add more "keys" to fetch referred to official documentation
    let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName)]

    // The container means 
    // that the source the contacts from, such as Exchange and iCloud
    var allContainers: [CNContainer] = []
    do {
        allContainers = try store.containersMatchingPredicate(nil)
    } catch {
        print("Error fetching containers")
    }

    var contacts: [CNContact] = []

    // Loop the containers
    for container in allContainers {
        let fetchPredicate = CNContact.predicateForContactsInContainerWithIdentifier(container.identifier)

        do {
            let containerResults = try store.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
            // Put them into "contacts"
            contacts.appendContentsOf(containerResults)
        } catch {
            print("Error fetching results for container")
        }
    }

【讨论】:

    【解决方案5】:

    用于拉入所有联系人的 Swift 4.0 实现。

    let contactStore = CNContactStore()
    var contacts = [CNContact]()
    let keys = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName)]
    let request = CNContactFetchRequest(keysToFetch: keys)
    
    do {
        try contactStore.enumerateContacts(with: request) { (contact, stop) in
            contacts.append(contact)
        }
    } catch {
        print(error.localizedDescription)
    }
    

    这会创建一个本地属性来存储联系人,然后通过针对contactStore 的枚举来填充这些联系人。

    【讨论】:

      【解决方案6】:

      请看我的答案,它是基于上面的答案并进行了某些改进,只需执行以下操作

      在您的 pod 文件中

      source 'https://github.com/CocoaPods/Specs.git'
      pod 'PhoneNumberKit', '~> 2.6'
      

      然后运行 ​​pod install

      然后在您的 ViewController 文件中

      import Contacts
      import PhoneNumberKit
      import UIKit
      
      override func viewDidLoad() {
          super.viewDidLoad()
      
          let contactStore = CNContactStore()
          var contacts = [CNContact]()
          let keys = [
              CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
              CNContactPhoneNumbersKey,
              CNContactEmailAddressesKey,
          ] as [Any]
          let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
          do {
              try contactStore.enumerateContacts(with: request) {
                  contact, _ in
                  // Array containing all unified contacts from everywhere
                  contacts.append(contact)
                  for phoneNumber in contact.phoneNumbers {
                      if let number = phoneNumber.value as? CNPhoneNumber, let label = phoneNumber.label {
                          let localizedLabel = CNLabeledValue<CNPhoneNumber>.localizedString(forLabel: label)
      
                          // Get The Name
                          let name = contact.givenName + " " + contact.familyName
                          print(name)
      
                          // Get The Mobile Number
                          var mobile = number.stringValue
                          mobile = mobile.replacingOccurrences(of: " ", with: "")
      
                          // Parse The Mobile Number
                          let phoneNumberKit = PhoneNumberKit()
      
                          do {
                              let phoneNumberCustomDefaultRegion = try phoneNumberKit.parse(mobile, withRegion: "IN", ignoreType: true)
                              let countryCode = String(phoneNumberCustomDefaultRegion.countryCode)
                              let mobile = String(phoneNumberCustomDefaultRegion.nationalNumber)
                              let finalMobile = "+" + countryCode + mobile
                              print(finalMobile)
                          } catch {
                              print("Generic parser error")
                          }
      
                          // Get The Email
                          var email: String
                          for mail in contact.emailAddresses {
                              email = mail.value as String
                              print(email)
                          }
                      }
                  }
              }
      
          } catch {
              print("unable to fetch contacts")
          }
      }
      

      【讨论】:

      • PhoneNumberKit 的性能非常昂贵,尤其是当您有超过 200 个联系人时
      • @UsmanShahid 你有什么更好的建议吗..谢谢..
      • 是的,使用这个库,它非常快速和准确(可以在swift和objective-c中使用)github.com/iziz/libPhoneNumber-iOS
      • 您的代码性能非常低,因为let phoneNumberKit = PhoneNumberKit() 这一行您为所有联系人运行此行,将其置于for 循环之外。
      • 使用PhoneNumberKit有什么好处?似乎默认的联系人库相当简单? ?‍♂️
      【解决方案7】:

      请尝试以下功能,它可以帮助您(Swift 4)

      import UIKit
      import Contacts
      import ContactsUI
      
      override func viewDidLoad() {
          super.viewDidLoad()
      
          // `contacts` Contains all details of Phone Contacts
          let contacts = self.getContactFromCNContact() 
          for contact in contacts {
      
              print(contact.middleName)
              print(contact.familyName)
              print(contact.givenName)
          }
      }
      
      func getContactFromCNContact() -> [CNContact] {
      
          let contactStore = CNContactStore()
          let keysToFetch = [
              CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
              CNContactGivenNameKey,
              CNContactMiddleNameKey,
              CNContactFamilyNameKey,
              CNContactEmailAddressesKey,
              ] as [Any]
      
          //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 as! [CNKeyDescriptor])
                  results.append(contentsOf: containerResults)
      
              } catch {
                  print("Error fetching results for container")
              }
          }
      
          return results
      }
      

      【讨论】:

        【解决方案8】:

        复杂的解决方案:

        var contacts = [CNContact]()
        
        let keys: [Any] = [
            CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
            CNContactImageDataKey,
            CNContactEmailAddressesKey,
            CNContactPhoneNumbersKey,
            CNContactJobTitleKey,
            CNContactBirthdayKey,
            CNContactPostalAddressesKey
        ]
        
        let request = CNContactFetchRequest(keysToFetch: keys as! [CNKeyDescriptor])
        let contactStore = CNContactStore()
        
        try? contactStore.enumerateContacts(with: request, usingBlock: { contact, _ in
            contacts.append(contact)
        })
        

        不要忘记 Info.plist:

        NSContactsUsageDescription
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-04-14
          • 2017-04-04
          • 2012-09-15
          • 1970-01-01
          • 1970-01-01
          • 2013-10-02
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多