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.
While it surprises me somewhat, I suspect that the
ABPersonis not completely defined without itsABAddressBook. 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 yourABAddressBookin 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 separateABAddressBookper thread.