how to retrive all CNContactStore from device without filter

前端 未结 3 882
傲寒
傲寒 2021-01-02 18:51

I\'m trying to insert into var contacts: [CNContact] = [] the var store = CNContactStore() but I did not find the right code for this job, i found

相关标签:
3条回答
  • 2021-01-02 19:22

    Modified Tommie C's answer for 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()
            }
    }
    
    0 讨论(0)
  • Update

    Based on comment from OP, please try the following CNContactFetchRequest-based API to retrieve all contacts without a filter. I run this on a background thread to reduce any possible issues huge numbers of contacts.

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

    Generally speaking you would normally set a predicate to nil to retrieve all of the contacts when using CNContactFetchRequest class rather than as described in your code.

    Note

    If you want to use your existing API then I recommend setting the predicate to true:

     NSPredicate(value: true)
    

    This should make all contacts return. If that does not work consider switching to the CNConctactFetchRequest API to enumerate the Contacts. In that event you could then set the predicate to nil to fetch all contacts (using CNConctactFetchRequest).

    This is how you might modify the existing method:

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

    And to use:

    let contacts = findContacts()
    

    Apple has a simpler sample:

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

    For your use-case, you could try to modify the Apple Sample like this:

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

    0 讨论(0)
  • 2021-01-02 19:32
    /// 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)
                        }
    
                    }
    
                }
    
            }
    
        }
    

    I am also using PhoneNumberKit to standardise all numbers and PromiseKit, to chain my requests, but you can pretty much adjust it whatever you want it.

    0 讨论(0)
提交回复
热议问题