0

I have a strange thing happening with ABAddressBook. Here is some code:

- (NSArray*)addressBookArray {

    ABAddressBookRef addressBook = NULL;
    NSArray *temp = nil;

    if(&ABAddressBookCreateWithOptions != NULL) {

        CFErrorRef error = nil;
        addressBook = ABAddressBookCreateWithOptions(NULL, &error);
        ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {

            dispatch_async(dispatch_get_main_queue(), ^{
                if(error) {
                    // handle error
                }
                else if(!granted) {
                    // handle not granted
                }
            });
        });
    }
    else { // iOS 5
        addressBook = ABAddressBookCreate();
    }
    if(addressBook) {
        temp = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
        CFRelease(addressBook);
    }
    return temp;
}

- (NSArray*)emailList {

    NSArray *temp = [self addressBookArray];
    NSMutableArray *list = nil;

    if(temp) {

        int n = temp.count;
        list = [NSMutableArray arrayWithCapacity:n];

        for(int i = 0; i < n ; i++) {

            ABRecordRef person = (__bridge ABRecordRef)[temp objectAtIndex:i];
            NSString *name = (__bridge_transfer NSString*)ABRecordCopyCompositeName(person);

            if(name) {
                ABMultiValueRef emails = ABRecordCopyValue(person, kABPersonEmailProperty);

                if(emails) {
                    int cnt = ABMultiValueGetCount(emails);

                    for(int j = 0; j < cnt; j++) {
                        NSString *email = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(emails, j);

                        if(email) {
                            [list addObject:email];
                            break;
                        }
                    }
                    CFRelease(emails);
                }
            }
        }
    }
    return list;
}

If I call emailList and comment out CFRelease(addressBook), I get a warning of a possible leak in XCode's Analyze, but my code behaves properly.

If I uncomment CFRelease(addressBook), there is no leak warning, ABRecordRef person and NSString *name have proper values, BUT ABMultiValueRef emails if always nil.

Confused.

Ty Kroll
  • 1,385
  • 12
  • 27

1 Answers1

2

While it surprises me somewhat, I suspect that the ABPerson is not completely defined without its ABAddressBook. So the address book needs to exist for as long as the person. Given that, as long as this is all single-threaded, you may want to store your ABAddressBook in an ivar so you don't have to create and destroy it all the time. If it's multi-threaded, remember that you need a separate ABAddressBook per thread.

Rob Napier
  • 286,113
  • 34
  • 456
  • 610