let store = CNContactStore()
let contacts = try store.unifiedContactsMatchingPredicate(CNContact.predicateForContactsMatchingName("Appleseed"), keysToFetch:[CNContactGivenNameKey, CNContactFamilyNameKey])
Both other answers do only load contacts from the container with the defaultContainerIdentifier. In a scenario, where the user has more than one container (i.e. an Exchange and an iCloud account which both are used to store contacts), this would only load the contacts from the account that is configured as the default. Therefore, it would not load all contacts as requested by the author of the question.
What you'll probably want to do instead is getting all the containers and iterate over them to extract all contacts from each of them. The following code snippet is an example of how we do it in one of our apps (in Swift):
lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey]
// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactStore.containersMatchingPredicate(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.predicateForContactsInContainerWithIdentifier(container.identifier)
do {
let containerResults = try contactStore.unifiedContactsMatchingPredicate(fetchPredicate, keysToFetch: keysToFetch)
results.appendContentsOf(containerResults)
} catch {
print("Error fetching results for container")
}
}
return results
}()
var results: [CNContact] = []
let fetchRequest = CNContactFetchRequest(keysToFetch: [CNContactGivenNameKey as CNKeyDescriptor, CNContactFamilyNameKey as CNKeyDescriptor, CNContactMiddleNameKey as CNKeyDescriptor, CNContactEmailAddressesKey as CNKeyDescriptor,CNContactPhoneNumbersKey as CNKeyDescriptor])
fetchRequest.sortOrder = CNContactSortOrder.userDefault
let store = CNContactStore()
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
print(contact.phoneNumbers.first?.value ?? "no")
results.append(contact)
})
}
catch let error as NSError {
print(error.localizedDescription)
}
Older version
for swift var results contains all contact
let contactStore = CNContactStore()
var results: [CNContact] = []
do {
try contactStore.enumerateContactsWithFetchRequest(CNContactFetchRequest(keysToFetch: [CNContactGivenNameKey, CNContactFamilyNameKey, CNContactMiddleNameKey, CNContactEmailAddressesKey,CNContactPhoneNumbersKey])) {
(contact, cursor) -> Void in
results.append(contact)
}
}
catch{
print("Handle the error please")
}
Right now in iOS9 ABAddressBookRef is deprecated so to fetch all contact from phone use this framework and add this function you will get array of contact.
Using Swift and Contacts framework to fetch all contacts, including name and phone numbers
import Contacts
let store = CNContactStore()
store.requestAccessForEntityType(.Contacts, completionHandler: {
granted, error in
guard granted else {
let alert = UIAlertController(title: "Can't access contact", message: "Please go to Settings -> MyApp to enable contact permission", preferredStyle: .Alert)
alert.addAction(UIAlertAction(title: "OK", style: .Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
return
}
let keysToFetch = [CNContactFormatter.descriptorForRequiredKeysForStyle(.FullName), CNContactPhoneNumbersKey]
let request = CNContactFetchRequest(keysToFetch: keysToFetch)
var cnContacts = [CNContact]()
do {
try store.enumerateContactsWithFetchRequest(request){
(contact, cursor) -> Void in
cnContacts.append(contact)
}
} catch let error {
NSLog("Fetch contact error: \(error)")
}
NSLog(">>>> Contact list:")
for contact in cnContacts {
let fullName = CNContactFormatter.stringFromContact(contact, style: .FullName) ?? "No Name"
NSLog("\(fullName): \(contact.phoneNumbers.description)")
}
})
Fetching contact is slow operation, so you should not block main UI thread. Do CNContactFetchRequest on background thread. That's why I put the code into completionHandler. It's run on a background thread.
let status : CNAuthorizationStatus = CNContactStore.authorizationStatusForEntityType(CNEntityType.Contacts)
if status == CNAuthorizationStatus.NotDetermined{
contactStore.requestAccessForEntityType(CNEntityType.Contacts, completionHandler: { (temp: Bool, error : NSError?) -> Void in
//call contacts fetching function
})
}else if status == CNAuthorizationStatus.Authorized {
//call contacts fetching function
})
}
else if status == CNAuthorizationStatus.Denied {
}
}
If no matches are found, this method returns an empty array (or nil in
case of error). Use only the predicates from the CNContact class
predicates. Compound predicates are not supported by this method. Due
to unification, the returned contacts may have different identifiers
than you specify. To fetch all contacts, use
enumerateContactsWithFetchRequest:error:usingBlock:.
@rocolitis 's answer in swift! His answer is the most correct way of doing this according to Apple's documentation.
let contactStore = CNContactStore()
let keys = [CNContactPhoneNumbersKey, CNContactFamilyNameKey, CNContactGivenNameKey, CNContactNicknameKey] as [CNKeyDescriptor]
let request = CNContactFetchRequest(keysToFetch: keys)
try? contactStore.enumerateContacts(with: request) { (contact, error) in
// Do something with contact
}
You should probably check your access to your contacts first!
let authorization = CNContactStore.authorizationStatus(for: CNEntityType.contacts)
switch authorization {
case .authorized: break
case .denied: break
case .restricted: break
case .notDetermined: break
}
In swift 3 and Xcode 8 you can get all contacts list
let keys = [CNContactGivenNameKey ,CNContactImageDataKey,CNContactPhoneNumbersKey]
var message: String!
//let request=CNContactFetchRequest(keysToFetch: keys)
let contactsStore = AppDelegate.AppDel.contactStore
// Get all the containers
var allContainers: [CNContainer] = []
do {
allContainers = try contactsStore.containers(matching: nil)
} catch {
print("Error fetching containers")
}
// 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 contactsStore.unifiedContacts(matching: fetchPredicate, keysToFetch: keys as [CNKeyDescriptor])
self.results.append(contentsOf: containerResults)
self.tableView.reloadData()
message="\(self.results.count)"
} catch {
print("Error fetching results for container")
}
}
I am trying this code it works fine. I can fetch all contacts details using this code in swift3 latest framework using contacts:
let requestForContacts = CNContactFetchRequest(keysToFetch: [CNContactIdentifierKey as CNKeyDescriptor, CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName), CNContactPhoneNumbersKey as CNKeyDescriptor ,CNContactImageDataKey as CNKeyDescriptor,CNContactEmailAddressesKey as CNKeyDescriptor,CNContactBirthdayKey as CNKeyDescriptor])
do {
try self.store.enumerateContacts(with: requestForContacts) { contact, stop in
print("contact:\(contact)")
self.contacts.append(contact)
}
} catch {
print(error)
}
for contact in self.contacts {
print(contact)
let firstName = contact.givenName
nameArray.append(firstName)
print("first:\(firstName)")
let phoneNumber = (contact.phoneNumbers[0].value).value(forKey: "digits")
phoneNumberArray.append(phoneNumber as! String)
let emailAddress = contact.emailAddresses[0].value(forKey: "value")
emailAddressArray.append(emailAddress as! String)
}
lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch: [CNKeyDescriptor] = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPostalAddressesKey as CNKeyDescriptor,
CNContactEmailAddressesKey as CNKeyDescriptor,
CNContactPhoneNumbersKey as CNKeyDescriptor,
CNContactImageDataAvailableKey as CNKeyDescriptor,
CNContactThumbnailImageDataKey as CNKeyDescriptor]
// 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)
results.append(contentsOf: containerResults)
} catch {
print("Error fetching results for container")
}
}
return results
}()
Original Answer:
Here is the Swift 3.0 version of flohei's answer
lazy var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: .fullName),
CNContactPostalAddressesKey,
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey] 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
}()
var contacts: [CNContact] = {
let contactStore = CNContactStore()
let keysToFetch = [
CNContactFormatter.descriptorForRequiredKeys(for: CNContactFormatterStyle.fullName),
CNContactEmailAddressesKey,
CNContactPhoneNumbersKey,
CNContactImageDataAvailableKey,
CNContactThumbnailImageDataKey] 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
}()
<key>NSContactsUsageDescription</key>
<string>$(PRODUCT_NAME) requires to access your contacts ...</string>
module:
import Contacts
code:
func fetchContacts(completion: @escaping (_ result: [CNContact]) -> Void){
DispatchQueue.main.async {
var results = [CNContact]()
let keys = [CNContactGivenNameKey,CNContactFamilyNameKey,CNContactMiddleNameKey,CNContactEmailAddressesKey,CNContactPhoneNumbersKey] as [CNKeyDescriptor]
let fetchRequest = CNContactFetchRequest(keysToFetch: keys)
fetchRequest.sortOrder = .userDefault
let store = CNContactStore()
store.requestAccess(for: .contacts, completionHandler: {(grant,error) in
if grant{
do {
try store.enumerateContacts(with: fetchRequest, usingBlock: { (contact, stop) -> Void in
results.append(contact)
})
}
catch let error {
print(error.localizedDescription)
}
completion(results)
}else{
print("Error \(error?.localizedDescription ?? "")")
}
})
}
}
Usage:
fetchContacts(completion: {contacts in
contacts.forEach({print("Name: \($0.givenName), number: \($0.phoneNumbers.first?.value.stringValue ?? "nil")")})
You need to describe the usage info in info.plist first.
I have added a check to determine user has granted the access to contacts then defined the keys (the values needed to be fetched). As said in one of the earlier answers that it's a time consuming process so I have added DispatchQueue for background processing and completion handler for returning the contacts array back to caller.