What ABRecordCopyValue can return? (solving a bad access)
Asked Answered
S

1

3

I'm using this simple code to get all contacts of the address book in ios 7. I have 155 contacts in my address. When i log people firstNames i obtain 34 correct names picked (apparently randomly) from my address book, 15 names null and then on item 50 a bad access crash on line

   NSString *firstNames = (__bridge NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty)

I tried loggin surname, or image getting no changes. I tried to avoid doing ABRecordCopyValue on null object getting no changes. I tried to execute ABRecordCopyValue on item >50 and got the same result on items from 50 to 150. What i'm doing wrong? What ABRecordCopyValue can return beside correct values and null?

+(NSArray *)getAllContactsAddress
{
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);

// SUPPOSE access has been granted
BOOL accessGranted = true;

if (accessGranted) {
    ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
    ABRecordRef source = ABAddressBookCopyDefaultSource(addressBook);
    CFArrayRef allPeople = ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering(addressBook, source, kABPersonSortByFirstName);
    CFIndex nPeople = ABAddressBookGetPersonCount(addressBook);
    NSMutableArray* items = [NSMutableArray arrayWithCapacity:nPeople];


    for (int i = 0; i < nPeople; i++)
    {
        ContactsData *contacts = [ContactsData new];

        ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);

        NSString *firstNames = (__bridge NSString*)ABRecordCopyValue(person, kABPersonFirstNameProperty);

        NSLog(@"%@",firstNames);
    }
}
Shala answered 9/7, 2014 at 10:51 Comment(5)
my error, sorry. In the original is nPeople without -1Shala
So where is it crashing? Can you provide a stacktrace?Terle
I don't know how to publish a stacktrace, sorry ^^ but it crashes, as i said in the question text, when executing ABRecordCopyValue(person, kABPersonFirstNameProperty) on the person number (i) 50 (for no apparent reason at all)Shala
And when it crashes does person == NULL?Terle
Tried and ok, i'm really confused. When it works (first 34 item), person is "CPRecord: 0x17db5b10 ABPerson>" (number changes). Then for 15 item is null (still working but with names null) and then at item 50 became "__NSCFType" and crashes.Shala
T
5

I think (I'm actually pretty sure) the issue is that nPeople is the wrong value and doesn't match the number of entries in the allPeople array, like you assume it does. You have used a strange method of getting nPeople when CFArray already provides a straight-forward method.

I reckon this will work:

CFIndex nPeople = CFArrayGetCount(allPeople);

Also you need to check if person is non-NULL before using it:

ABRecordRef person = CFArrayGetValueAtIndex(allPeople, i);
NSAssert(person, @"Non-person detected!");
Terle answered 9/7, 2014 at 11:3 Comment(4)
Yes, this is right (Thank you, it's working), but i have still a problem: why i'm getting only 34 contacts instead of 155? So the problem was in ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering that is not getting really allPeople as it is meant to do?Shala
@ElisabettaFalivene That's probably cos you asked the address book to return entries sorted by first-name? Use another method perhaps? Also if I have provided some help, how about an upvote?Terle
Still makes no totally sense to me, but solved the problem using ABAddressBookCopyArrayOfAllPeople instead of ABAddressBookCopyArrayOfAllPeopleInSourceWithSortOrdering. In the second case, function returned a subset of items in the address book, instead of all. Thank you for helping!Shala
The address book is a compilation of records from multiple sources - like Facebook, iCloud, etc. Default source is addresses that were entered into Contacts, rather than synced from some other source like an exchange server. So if you had 155 contacts, but 121 of them were synced from an exchange server, you would only receive 34 contacts if you retrieved the contacts from the default source as you were doing. If you want every contact regardless of its source, ABAddressBookCopyArrayOfAllPeople is the correct way to do it.Creation

© 2022 - 2024 — McMap. All rights reserved.