1

I use the following code to remove all contacts I have inserted in the address book, depending on the group they have been added to :

ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);

NSArray* contactsArray = (__bridge NSArray *)(ABGroupCopyArrayOfAllMembers([self ABGetAddressGroup:addressBook]));

if (contactsArray.count) {

    for (NSUInteger index = 0 ; index < contactsArray.count; index++) {

        ABRecordRef person = (__bridge ABRecordRef)(contactsArray[index]);

        ABAddressBookRemoveRecord(addressBook, person, NULL);
    }

    CFRelease((__bridge CFTypeRef)contactsArray);

    NSArray *groups = (__bridge NSArray *) ABAddressBookCopyArrayOfAllGroups(addressBook);

    for (id _group in groups) {

        NSString *currentGroupName = (__bridge NSString*) ABRecordCopyValue((__bridge ABRecordRef)(_group), kABGroupNameProperty);

        if ([[self getDatabase] isEqualToString:currentGroupName]) {

            ABAddressBookRemoveRecord(addressBook, (__bridge ABRecordRef)(_group), NULL);
        }

        CFRelease((__bridge CFTypeRef)(currentGroupName));
    }

    CFRelease((__bridge CFTypeRef)(groups));
}

if (ABAddressBookHasUnsavedChanges(addressBook)) {//potential leak of an object stored in contactsArray

    //Save recent changes
    ABAddressBookSave(addressBook, NULL);

} else {

    NSLog(@"Nothing to do here, let's eat cake");
}

CFRelease(addressBook);

The Analyzer show a warning (if that's what it's called) in the ABAddressBookHasUnsavedChanges...potential leak of an object stored in contactsArray. What do I need to do to get rid of this?

If use CFRelease as follows:

CFRelease((__bridge CFTypeRef)(contactsArray));

the analyzer says : Reference-counted object is used after it is released, even if it released at the end of the non-returning method, and the app crashes.

What am I doing wrong here? How do I get rid of such memory leaks?

n00bProgrammer
  • 4,261
  • 3
  • 32
  • 60

1 Answers1

3

your problem is in this line:

CFRelease((__bridge CFTypeRef)contactsArray);

because this line runs only when the if statement's true-branch is executed, therefore nothing releases the contactsArray in every other scenarios. that is pure a leak here.

luckily, there are two ways to solve such simple problem.

Option #1

passing the ownership to ARC:

NSArray* contactsArray = (__bridge_transfer NSArray *)(ABGroupCopyArrayOfAllMembers([self ABGetAddressGroup:addressBook]));

if (contactsArray.count) {
     // (...)

     // CFRelease((__bridge CFTypeRef)contactsArray);

     // (...)
}

Option #2

making sure to release the object in any case:

NSArray* contactsArray = (__bridge NSArray *)(ABGroupCopyArrayOfAllMembers([self ABGetAddressGroup:addressBook]));

if (contactsArray.count) {
     // (...)

     // CFRelease((__bridge CFTypeRef)contactsArray);

     // (...)
}

if (contactsArray) CFRelease((__bridge CFTypeRef)contactsArray);

something like this could help on you, I guess.

holex
  • 23,961
  • 7
  • 62
  • 76
  • The `CFRelease()` was placed inside `if` to avoid `NULL` releases, which would cause app crashes. Option #1 was enough. Letting ARC take over seems to be working. Thank you. – n00bProgrammer May 21 '14 at 06:38