如何在没有过滤器的情况下从设备检索所有 CNContactStore

how to retrive all CNContactStore from device without filter

我正在尝试插入 var contacts: [CNContact] = [] var store = CNContactStore() 但我没有找到适合这项工作的代码,我找到了这个函数,我需要给它起一个名字

func findContactsWithName(name: String) {
    AppDelegate.sharedDelegate().checkAccessStatus({ (accessGranted) -> Void in
        if accessGranted {
            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                do {
                    let predicate: NSPredicate = CNContact.predicateForContactsMatchingName(name)
                    let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactBirthdayKey, CNContactViewController.descriptorForRequiredKeys()]
                    self.contacts = try self.store.unifiedContactsMatchingPredicate(predicate, keysToFetch:keysToFetch)


                    self.tableView.reloadData()
                }
                catch {
                    print("Unable to refetch the selected contact.")
                }
            })
        }
    })
}

我想插入 self.contacts 所有记录,而不仅仅是同名的记录

更新

根据 OP 的评论,请尝试以下基于 CNContactFetchRequest 的 API 来检索所有没有过滤器的联系人。我 运行 这是在后台线程上进行的,以减少大量联系人可能出现的任何问题。

func findContactsOnBackgroundThread ( completionHandler:(contacts:[CNContact]?)->()) {

        dispatch_async(dispatch_get_global_queue(QOS_CLASS_USER_INITIATED, 0), { () -> Void in

            let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),CNContactPhoneNumbersKey] //CNContactIdentifierKey
            let fetchRequest = CNContactFetchRequest( keysToFetch: keysToFetch)
            var contacts = [CNContact]()
            CNContact.localizedStringForKey(CNLabelPhoneNumberiPhone)

            fetchRequest.mutableObjects = false
            fetchRequest.unifyResults = true
            fetchRequest.sortOrder = .UserDefault

            let contactStoreID = CNContactStore().defaultContainerIdentifier()
            print("\(contactStoreID)")


            do {

                try CNContactStore().enumerateContactsWithFetchRequest(fetchRequest) { (contact, stop) -> Void in
                    //do something with contact
                    if contact.phoneNumbers.count > 0 {
                        contacts.append(contact)
                    }

                }
            } catch let e as NSError {
                print(e.localizedDescription)
            }

            dispatch_async(dispatch_get_main_queue(), { () -> Void in
                completionHandler(contacts: contacts)

            })
        })
    }

一般来说,您通常会在使用 CNContactFetchRequest class 时将谓词设置为 nil 以检索所有联系人,而不是像您的代码中描述的那样。

备注

如果您想使用现有的 API,那么我建议将谓词设置为 true:

 NSPredicate(value: true)

这应该使所有联系人 return。如果这不起作用,请考虑切换到 CNConctactFetchRequest API 以枚举联系人。在这种情况下,您可以将谓词设置为 nil 以获取所有联系人(使用 CNConctactFetchRequest)。

这是您修改现有方法的方式:

func findContacts()->[CNContact] {
        AppDelegate.sharedDelegate().checkAccessStatus({ (accessGranted) -> Void in
            if accessGranted {
                dispatch_async(dispatch_get_main_queue(), { () -> Void in
                    do {
                        let predicate: NSPredicate = NSPredicate(value: true)
                        let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactBirthdayKey, CNContactViewController.descriptorForRequiredKeys()]
                        self.contacts = try self.store.unifiedContactsMatchingPredicate(predicate, keysToFetch:keysToFetch)


                        self.tableView.reloadData()
                    }
                    catch {
                        print("Unable to refetch the selected contact.")
                    }
                })
            }
        })
    }

并使用:

let contacts = findContacts()

Apple 有一个更简单的示例:

let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingName("Appleseed"), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])

对于您的用例,您可以尝试像这样修改 Apple 示例:

//Use the reference to look up additional keys constants that you may want to fetch
let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(NSPredicate(value: true), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])

More Apple Samples for the Contacts Framework

修改了 Tommie C 对 XCode 8 & Swift 3.0 的回答。

func findContactsOnBackgroundThread ( completionHandler:@escaping (_ contacts:[CNContact]?)->()) {

    DispatchQueue.global(qos: .userInitiated).async(execute: { () -> Void in

        let keysToFetch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName),CNContactPhoneNumbersKey] as [Any] //CNContactIdentifierKey
        let fetchRequest = CNContactFetchRequest( keysToFetch: keysToFetch as! [CNKeyDescriptor])
        var contacts = [CNContact]()
        CNContact.localizedString(forKey: CNLabelPhoneNumberiPhone)

        if #available(iOS 10.0, *) {
            fetchRequest.mutableObjects = false
        } else {
            // Fallback on earlier versions
        }
        fetchRequest.unifyResults = true
        fetchRequest.sortOrder = .userDefault

        let contactStoreID = CNContactStore().defaultContainerIdentifier()
        print("\(contactStoreID)")


        do {

            try CNContactStore().enumerateContacts(with: fetchRequest) { (contact, stop) -> Void in
                //do something with contact
                if contact.phoneNumbers.count > 0 {
                    contacts.append(contact)
                }

            }
        } catch let e as NSError {
            print(e.localizedDescription)
        }

        DispatchQueue.main.async(execute: { () -> Void in
            completionHandler(contacts)

        })
    })
} 

override func viewDidLoad() {
    findContactsOnBackgroundThread { (contacts) in
            self.contactsList = contacts
            self.tableView.reloadData()
        }
}
/// The default key descriptors to fetch
public var defaultFetchKeys: [String] = [CNContactGivenNameKey,
                                         CNContactFamilyNameKey,
                                         CNContactPhoneNumbersKey,
                                         CNContactImageDataAvailableKey,
                                         CNContactThumbnailImageDataKey]

/**
     Fetch contacts from the user's device

     - parameter sortOrder: The sort order that should be used. Default none.
     - returns: A list of contacts
     */
    public func fetchContacts(withSortOrder sortOrder: CNContactSortOrder = .givenName,
                              qos: DispatchQoS.QoSClass = .background) -> Promise<[Contact]>
    {

        return Promise { seal in

            DispatchQueue.global(qos: qos).async {

                let store = CNContactStore()
                var contacts = [Contact]()

                /// A `PhoneNumberKit` object used to parse and format numbers (expensive!)
                let phoneNumberKit = PhoneNumberKit()

                let request = CNContactFetchRequest(keysToFetch: self.defaultFetchKeys as [CNKeyDescriptor])
                request.sortOrder = sortOrder
                request.unifyResults = true

                do {

                    try store.enumerateContacts(with: request) { contact, _ in

                        if let user = Contact(contact: contact, kit: phoneNumberKit) {
                            contacts.append(user)
                        }

                    }

                    DispatchQueue.main.async {
                        seal.fulfill(contacts)
                    }

                } catch {

                    DispatchQueue.main.async {
                        seal.reject(error)
                    }

                }

            }

        }

    }

我还使用 PhoneNumberKit 来标准化所有数字,并使用 PromiseKit 来链接我的请求,但您几乎可以根据需要对其进行调整。