I need to get the number of all contacts on a user's device. The deprecation message on ABAddressBookGetPersonCount says:
use count of fetch results for CNContactFetchRequest with predicate = nil
Here is what I made up following that guidance:
__block NSUInteger contactsCount = 0;
NSError *error;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[CNContactGivenNameKey]];
BOOL success = [self.contactStore enumerateContactsWithFetchRequest:request error:&error
usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
contactsCount += 1;
}];
if (!success || error) {
NSLog(@"error counting all contacts, error - %@", error.localizedDescription);
}
However this looks terrible in terms of performance. I have not found another way of getting the count without enumerating CNContact objects. Am I missing something?
Thank you in advance!
This is old, but in case anyone else stumbles upon it, it can be accomplished by doing the enumeration with 0 keys to fetch instead of 1.
__block NSUInteger contactsCount = 0;
NSError *error;
CNContactFetchRequest *request = [[CNContactFetchRequest alloc] initWithKeysToFetch:@[]];
BOOL success = [self.contactStore enumerateContactsWithFetchRequest:request error:&error
usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) {
contactsCount += 1;
}];
if (!success || error) {
NSLog(@"error counting all contacts, error - %@", error.localizedDescription);
}
With 0 keys, I was able to run the count on a device with 10,000 contacts in 0.8 seconds (whereas it took 14 seconds with 1 key).
Swift 3 version, packaged as a Class function.
class func contactCount() -> Int? {
let contactStore = CNContactStore()
var contactsCount: Int = 0
let contactFetchRequest = CNContactFetchRequest(keysToFetch: [])
do {
try contactStore.enumerateContacts(with: contactFetchRequest) { (contact, error) in
contactsCount += 1
}
} catch {
print("Error counting all contacts.\nError: \(error)")
return nil
}
return contactsCount
}
Often it will be better to reuse a contact store than create another one:
class func contactCount(store: CNContactStore?) -> Int? {
let contactStore: CNContactStore
if let suppliedStore = store {
contactStore = suppliedStore
} else {
contactStore = CNContactStore()
}
var contactsCount: Int = 0
let contactFetchRequest = CNContactFetchRequest(keysToFetch: [])
do {
try contactStore.enumerateContacts(with: contactFetchRequest) { (contact, error) in
contactsCount += 1
}
} catch {
print("Error counting all contacts.\nError: \(error)")
return nil
}
return contactsCount
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With