Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ABAddressBookCopyArrayOfAllPeople and ABAddressBookGetPersonCount return different sizes

I have an app which crashes occasionally due to the array returned by ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering() having a different size to ABAddressBookGetPersonCount(). The shell of the code is shown below. Usually nPeople is the same size as the array. However, on one user's iPhone (or at least, as reported by one user), nPeople is almost twice as large. I can stop the crash by using the array size, rather than ABAddressBookGetPersonCount(). However, I am not sure if this means I am not accessing all of the Contacts in the iPhone.

  • Has anyone come across this issue before?
  • Why would the numbers be different?

I wondered if it was something to do with the contacts being stored in Groups (I do not know that there are groups - just an idea). Also, from the user's email address, I suspect they use MobileMe. I wondered if syncing with MobileMe would create duplicates with a different recordId, but not delete the existing Contact, at least not as far as ABAddressBookGetPersonCount() goes.

EDIT: I have looked into this some more and have a fairly good idea at the cause of the problem. As I wanted a sorted array of contacts, I used ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(). This requires an address book source - I used the default source. I believe there can be various sources - the local source plus others such as Exchange and MobileMe. Therefore, my array will end up with just the local contacts, whereas the number returned by ABAddressBookGetPersonCount() will include all sources - hence my crash. Therefore, I think it would be better to just work with the local data in my app and use the array size returned by ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering rather than ABAddressBookGetPersonCount.

CFArrayRef allPeople = InSourceWithSortOrdering(addressBook, source, kABPersonSortByLastName);  

    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (int i = 0; i < nPeople; i++) 
    {
        ABRecordRef ref = CFArrayGetValueAtIndex(allPeople, i);
    }   
like image 850
guinnessman Avatar asked Sep 19 '11 16:09

guinnessman


3 Answers

ABAddressBookGetPersonCount And ABAddressBookCopyArrayOfAllPeople gives different arrays.

ABAddressBookGetPersonCount - Returns the number of person records in an address book. ABAddressBookCopyArrayOfAllPeople - Returns all the person records in an address book.

So some times same person may have extra records. That's why you may getting different sizes.

like image 150
Somnath Muluk Avatar answered Nov 15 '22 00:11

Somnath Muluk


I meet this problem today. My app also crashes in some special iDevices.

code:

    ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByLastName);

    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (int i = 0; i < nPeople; i++) {
        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
        // more thing with `person`
    }

But it will crash sometimes. Adding some breakpoints I found that allPeople's count is less than nPeople.

By googling, I found this article. I found that maybe there's something wrong with ABAddressBookCopyDefaultSource. Here I got the default source, I have to got all sources instead.

code:

CFArrayRef sources = ABAddressBookCopyArrayOfAllSources(addressBook);

CFIndex sourceCount = CFArrayGetCount(sources);

for (CFIndex i = 0; i < sourceCount; i++) {
    ABRecordRef currentSource = CFArrayGetValueAtIndex(source, i);
    int sourceType = [(__bridge NSNumber *)ABRecordCopyValue(currentSource, kABSourceTypeProperty) intValue];
    switch (sourceType) {

        case kABSourceTypeCardDAV:
            NSLog(@"kABSourceTypeCardDAV");
            break;

        case kABSourceTypeCardDAVSearch:
            NSLog(@"kABSourceTypeCardDAVSearch");
            break;

        case kABSourceTypeExchange:
            NSLog(@"kABSourceTypeExchange");
            break;

        case kABSourceTypeExchangeGAL:
            NSLog(@"kABSourceTypeExchangeGAL");
            break;

        case kABSourceTypeLDAP:
            NSLog(@"kABSourceTypeLDAP");
            break;

        case kABSourceTypeLocal:
            NSLog(@"kABSourceTypeLocal");
            break;

        case kABSourceTypeMobileMe:
            NSLog(@"kABSourceTypeMobileMe");
            break;

        default:
            break;
    }
    CFArrayRef allPeopleInSource = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, currentSource, kABPersonSortByLastName);
    NSLog(@"Count of allPeopleInSource: %i", CFArrayGetCount(allPeopleInSource));
}

Then I got

    kABSourceTypeCardDAV
    Count of allPeopleInSource: 7

which means there is only one source and only 7 records in that source.

But in my address book, I have 79 contacts!

Then I made a mistake. I passed the sources to ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering, just like this:

    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, sources, kABPersonSortByLastName);

How many members in allPeople?

72!!!

Exactly the count of records which are not in sources.

I passed a CFArrayRef to ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering as the second parameter, which expects a ABRecordRef. What if I pass nil?

Finally, I got the codes:

    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, nil, kABPersonSortByLastName);

    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);

    for (int i = 0; i < nPeople; i++) {
        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
        // more thing with `person`
    }

Now I can get all of the contacts in my address book.

It works fine on all of my iDevices!

I'm very sorry about my poor english...

Hopefully, this answer can help you.

Note: Now I don't understand what is source in AddressBook exactly, Can anybody help me?

like image 9
Jokinryou Tsui Avatar answered Nov 14 '22 22:11

Jokinryou Tsui


@Jokinryou Tsui Passing source as nil was the key, thanks! It seems like the source types may correspond to this documentation from Apple : https://developer.apple.com/library/ios/documentation/AddressBook/Reference/ABSourceRef_iPhoneOS/#//apple_ref/doc/constant_group/Source_Types

like image 3
yuebai Avatar answered Nov 14 '22 23:11

yuebai