iPhone SDK: EXC_BAD_ACCESS with CFRelease for ABAddressBookRef
Asked Answered
A

2

5

there's very strange error with my code.. In fact, there's no errors at all, just debugger starts with "Program received signal: “EXC_BAD_ACCESS”" message. Can anyone help me? I'm absolutely confused... Thank you.

-(NSString *)fullNameForPhone:(NSString *)ph withAlternativeText:(NSString *)text
{
    ABAddressBookRef addressBookRef = ABAddressBookCreate(); 
    NSLog(@"create addressBookRef");
    NSString *stringToReturn = text;

    CFArrayRef allPeopleRef = ABAddressBookCopyArrayOfAllPeople(addressBookRef);  
    NSLog(@"create allPeopleRef");
    CFIndex nPeople = ABAddressBookGetPersonCount(addressBookRef);  

    int i = 0;
    BOOL nameFound = NO;

    while ((i < nPeople) && (!nameFound))
    {
        ABRecordRef recordRef = CFArrayGetValueAtIndex(allPeopleRef, i);
        NSLog(@"   create recordRef");
        CFStringRef allRecordPhonesRef = ABRecordCopyValue(recordRef, kABPersonPhoneProperty);
        NSLog(@"   create allRecordPhonesRef");
        CFIndex nPhones = ABMultiValueGetCount(allRecordPhonesRef);
        int currentPhone = 0;
        for (currentPhone = 0; currentPhone < nPhones; currentPhone++) 
        {
            CFStringRef currentPhoneNumberRef = ABMultiValueCopyValueAtIndex(allRecordPhonesRef, currentPhone);
            NSLog(@"         create currentPhoneNumberRef");
            NSString *currentCleanPhoneNumber = [self cleanPhoneNumberForString:[NSString stringWithFormat:@"%@", currentPhoneNumberRef]];
            if (currentPhoneNumberRef!=NULL)
            {
                NSLog(@"         release currentPhoneNumberRef");
                CFRelease(currentPhoneNumberRef);
            }

            if ([ph isEqualToString:currentCleanPhoneNumber])
            {
                CFStringRef firstName = ABRecordCopyValue(recordRef, kABPersonFirstNameProperty);
                CFStringRef lastName = ABRecordCopyValue(recordRef, kABPersonLastNameProperty);
                NSString *fullName = [self fullNameForFirstName:[NSString stringWithFormat:@"%@", firstName] 
                                                    andLastName:[NSString stringWithFormat:@"%@", lastName]];
                if (firstName != NULL)
                    CFRelease(firstName);
                if (lastName != NULL)
                    CFRelease(lastName);
                stringToReturn = fullName;
                nameFound = YES;
                break;
            }

        }

        CFRelease(allRecordPhonesRef);
        NSLog(@"   release allRecordPhonesRef");
        CFRelease(recordRef);
        NSLog(@"   release recordRef");
        i++;
    }
    CFRelease(allPeopleRef);
    NSLog(@"release allPeopleRef");
    CFRelease(addressBookRef);
    NSLog(@"release addressBookRef");
    return stringToReturn;
}

Console output is:

2009-07-31 00:20:05.230 abmodular[21747:20b] create addressBookRef
2009-07-31 00:20:05.231 abmodular[21747:20b] create allPeopleRef
2009-07-31 00:20:05.231 abmodular[21747:20b]    create recordRef
2009-07-31 00:20:05.232 abmodular[21747:20b]    create allRecordPhonesRef
2009-07-31 00:20:05.232 abmodular[21747:20b]          create currentPhoneNumberRef
2009-07-31 00:20:05.232 abmodular[21747:20b]          release currentPhoneNumberRef
2009-07-31 00:20:05.232 abmodular[21747:20b]          create currentPhoneNumberRef
2009-07-31 00:20:05.233 abmodular[21747:20b]          release currentPhoneNumberRef
2009-07-31 00:20:05.233 abmodular[21747:20b]    release allRecordPhonesRef
2009-07-31 00:20:05.233 abmodular[21747:20b]    release recordRef
2009-07-31 00:20:05.233 abmodular[21747:20b]    create recordRef
2009-07-31 00:20:05.234 abmodular[21747:20b]    create allRecordPhonesRef
2009-07-31 00:20:05.234 abmodular[21747:20b]          create currentPhoneNumberRef
2009-07-31 00:20:05.234 abmodular[21747:20b]          release currentPhoneNumberRef
2009-07-31 00:20:05.234 abmodular[21747:20b]    release allRecordPhonesRef
2009-07-31 00:20:05.235 abmodular[21747:20b]    release recordRef
2009-07-31 00:20:05.235 abmodular[21747:20b] release allPeopleRef
[Session started at 2009-07-31 00:20:05 +0400.]
GNU gdb 6.3.50-20050815 (Apple version gdb-966)
....
Attaching to process 21747.
kill
quit
The Debugger has exited with status 0.(gdb) 

Pressing Continue outputs "EXC_BAD_ACCESS" message. Xcode shows, that the latest executed string in my code was CFRelease(addressBookRef);

Ambulance answered 30/7, 2009 at 20:26 Comment(0)
N
15

I had the same issue doing something similiar and upon further research I discovered I was over releasing. According to the Core Foundation docs:

If you create or copy a Core Foundation object, you must subsequently release it when you’re finished with it.

I read that as meaning that functions with the word Get should not be released by you. If you do, it will cause an issue later on when the real owner attempts to release it. So, in this case when you do:

ABRecordRef recordRef = CFArrayGetValueAtIndex(allPeopleRef, i);

and later:

CFRelease(recordRef);

you are releasing something that is not supposed to be released. Much later when you do:

CFRelease(allPeopleRef);

the array will attempt to release all its records not knowing you have already released some of them. The result is your error. By commenting out that line you may have made the error go away but I fear you have created a memory leak.

I suggest you do not call CFRelease on Get method pointers and do call it on Create or Copy method pointers (there may be exceptions to this rule but so far it works for me).

Nicias answered 26/8, 2009 at 19:56 Comment(1)
Thank you very much. Now there's no leaking.Ambulance
M
-2

allPeopleRef and addressBookRef point to the same objects? The copy is probably shallow. What does ABAddressBookCopyArrayOfAllPeople do?

Metabolize answered 30/7, 2009 at 20:45 Comment(4)
ABAddressBookCopyArrayOfAllPeople Returns all the person records in an address book. CFArrayRef ABAddressBookCopyArrayOfAllPeople ( ABAddressBookRef addressBook ); Parameters addressBook The address book whose person records to return. Return Value Array containing the person records in addressBook. Availability Available in iPhone OS 2.0 and later. Declared In ABPerson.hAmbulance
What happens if you comment out CFRelease(allPeopleRef); ?Metabolize
Thank you for reply! After commenting out CFRelease(allPeopleRef); it works correctly now! Thank you. Why addressBookRef and allPeopleRef points to the same objects? I thought that ABAddressBookCopyArrayOfAllPeople function will return at least copy of all records..Ambulance
[.. copy] is really a shallow copy. If you want to learn about deep copying you can look at the NSCoding protocol for more information.Metabolize

© 2022 - 2024 — McMap. All rights reserved.