CNContactStore count of contact records
Asked Answered
C

2

7

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!

Contemn answered 18/4, 2016 at 13:34 Comment(2)
How is your code anything like the suggestion in the deprecation message?Agueda
Is there another way to execute a CNContactFetchRequest?Contemn
I
2

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

Infrequent answered 19/4, 2017 at 22:0 Comment(1)
That is actually a very good point! I still wish Apple add a legit way to have this count. Ingurss a simple cached property would be the only proper way to go. Thanks again for the insight.Contemn
N
1

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
} 
Navarrette answered 29/6, 2017 at 5:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.