如何在没有过滤器的情况下从设备检索所有 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])
修改了 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
来链接我的请求,但您几乎可以根据需要对其进行调整。
我正在尝试插入 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])
修改了 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
来链接我的请求,但您几乎可以根据需要对其进行调整。