5

I am running into a situation where ABAddressBookGetPersonCount is returning -1. The tester assures me there contacts do exist in the address book. All the handsets are running iOS 6.0.1.

Here's the code:

NSMutableDictionary *myAddressBook = [[NSMutableDictionary alloc] init];
ABAddressBookRef addressBook = ABAddressBookCreate();
CFArrayRef people  = ABAddressBookCopyArrayOfAllPeople(addressBook);
int numEntries = ABAddressBookGetPersonCount(addressBook);
if (numEntries == 0)
{
    NSString *title = NSLocalizedString(@"error", nil);
    NSString *description =  NSLocalizedString(@"error_empty_contacts", nil);
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle:title
                                                    message:description
                                                   delegate:self
                                          cancelButtonTitle:@"OK"
                                          otherButtonTitles:nil];
    [alert show];


    return;
}

NSLog(@"emails: found %d", numEntries);

I am not able to reproduce this on any of my handsets, but the tester has tried on 3 handsets. It works properly on an iPhone 5, but not on a 4 or 3;

I can't find any docs that indicate what a value of -1 means. I'm assuming it's an error of some kind, but what?

TimF
  • 151
  • 1
  • 2
  • 8

1 Answers1

3

Under iOS 6, this code isn't valid. You have to verify that your app has permission to access the address book. Most likely, the -1 is an indication that the app has no permission (or an unknown permission state) on those devices.

From the docs for ABAddressBookRequestAccessCompletionHandler:

CFErrorRef myError = NULL;
ABAddressBookRef myAddressBook = ABAddressBookCreateWithOptions(NULL, &myError);
APLViewController * __weak weakSelf = self;  // avoid capturing self in the block
ABAddressBookRequestAccessWithCompletion(myAddressBook,
  ^(bool granted, CFErrorRef error) {
    if (granted) {
        NSArray *theSmiths = CFBridgingRelease(
          ABAddressBookCopyPeopleWithName(myAddressBook,
            CFSTR("Smith")
          )
        );
        weakSelf.numberOfSmiths = [theSmiths count];
    } else {
        // Handle the error
    }
});
CFRelease(myAddressBook);

If you need to support iOS 5.x or 4.x you need to properly check for the existence of the new methods.

rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • I'm also getting -1 in iOS 6 in the case where the user has not yet tapped an option on the privacy prompt on the app's first startup. In that case, ABAddressBookCreateWithOptions returns a valid address book, but ABAddressBookGetPersonCount returns -1. Once the user has chosen to allow or deny access, ABAddressBookCreateWithOptions returns the actual addressbook or null. I'm using the -1 return to detect whether the user has granted access. – Nicholas Jan 08 '13 at 17:28
  • 1
    @Nicholas The proper way to check is to call the `ABAddressBookGetAuthorizationStatus` function and check its return value. – rmaddy Jan 08 '13 at 17:33
  • Thanks @rmaddy. I had tried that before but was unable to get reliable data from it. Now that I know more about how this works and how to test it, it seems to be giving me what I need to know. The answer regarding -1 from ABAddressBookGetPersonCount still holds, however. It's pretty clear, though undocumented, that -1 is returned when ABAddressBookGetAuthorizationStatus returns kABAuthorizationStatusNotDetermined. – Nicholas Jan 08 '13 at 17:41