【问题标题】:how to retrive all CNContactStore from device without filter如何从没有过滤器的设备中检索所有 CNContactStore
【发布时间】:2015-10-26 14:52:59
【问题描述】:

我正在尝试插入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所有记录,而不仅仅是一个名称相等的记录

【问题讨论】:

  • 您好,下面的代码行将给出名字、姓氏、生日。 ** let keysToFetch = [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactBirthdayKey, CNContactViewController.descriptorForRequiredKeys()]** 如果我想检索联系人的所有详细信息如何获取?。

标签: ios swift cncontact


【解决方案1】:

更新

根据 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 类时将谓词设置为 nil 来检索所有联系人,而不是按照代码中的描述。

注意

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

 NSPredicate(value: true)

这应该使所有联系人返回。如果这不起作用,请考虑切换到 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

【讨论】:

  • 由于未捕获的异常“CNInvalidPredicateException”,我正在终止应用程序,原因:“谓词 TRUEPREDICATE 不是有效的联系人谓词
  • @shaharnakash - 请参阅提供的 CNContactFetchRequest 示例。请让我知道这是否适用于您的情况?
  • C 现在可以工作了,我按照您的建议使用 let fetchRequest = CNContactFetchRequest(keysToFetch: keysToFetch) 现在一切都完美了:)
  • 嘿,汤米!我刚刚使用我的朋友 iPhone 运行了这段代码,我们只得到了整个联系人的 10% 左右。你知道什么会导致这种情况吗?或者,无论来源如何,我们如何才能收到整个联系人列表?
  • @RoiMulia - 我不确定您何时何地调用此代码,但请注意,在窗口事件等位置调用后台线程可能会导致 Apple 框架使用的竞争线程出现问题。我会尝试从 viewDidLoad 或某些操作中调用代码,但请记住线程可能会导致竞争条件。另外,请确保您使用统一的联系人设置......也可能是其他事情,没有更多上下文我无法判断。如果这些建议对您有帮助,请告诉我。
【解决方案2】:

修改了 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()
        }
}

【讨论】:

    【解决方案3】:
    /// 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 来链接我的请求,但您几乎可以随意调整它。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2019-10-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-02-18
      相关资源
      最近更新 更多