ABMultilValueGetIndexForIdentifier returns incorrect Index when Contact has LinkedContacts

163 views Asked by At

I've noticed a bug in the logic we use to handle the selection of a specific email for a contact presented by an ABPeoplePickerNavigationController. The bug occurs specifically when we the contact has Linked Contacts, from Twitter or Facebook.

I've double checked our logic against several related StackOverflow questions and I seem to be doing everything "Correctly":

Here is the code for loading up the ABPeoplePicker after a button is tapped:

- (void)setUpChooseContactButton
{
    @weakify(self)
    [self.chooseContactButton addEventHandler:^(id sender) {

        @strongify(self)
        ABPeoplePickerNavigationController *picker = [[ABPeoplePickerNavigationController alloc] init];
        picker.peoplePickerDelegate = self;
        picker.displayedProperties = @[@(kABPersonEmailProperty)];

        picker.delegate = self;

        [self presentViewController:picker animated:YES completion:nil];

    } forControlEvents:UIControlEventTouchUpInside];
}

Later, when a user taps an email for a selected contact, we handle it as follows:

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker
      shouldContinueAfterSelectingPerson:(ABRecordRef)person
                                property:(ABPropertyID)property
                              identifier:(ABMultiValueIdentifier)identifier
{
    if (property == kABPersonEmailProperty)
    {
        ABMultiValueRef multiEmail = ABRecordCopyValue(person, kABPersonEmailProperty);
        CFIndex selectedIndex = ABMultiValueGetIndexForIdentifier(multiEmail, identifier);
        CFStringRef selectedEmail = ABMultiValueCopyValueAtIndex(multiEmail, selectedIndex);
        NSLog(@"Doing something with %@", selectedEmail);
        if (selectedEmail) CFRelease(selectedEmail);
        if (multiEmail) CFRelease(multiEmail);
    }

    [self dismissViewControllerAnimated:YES completion:nil];

    return NO;
}

This works perfectly when the contact doesn't have any linked contacts, e.g. Facebook, however, when it does the email address printed here won't be the one selected by the user.

For example, I have a friend in my contacts who we'll call John Snow, we're good friends so I'm connected with him on iCloud, 2 different gmail accounts, and Facebook.

When I navigate to John Snow's contact page, I see the following 5 emails:

As well as cells for each of the linked contacts.

So if I tap on [email protected] (index of 2 in the list of presented emails) and have a breakpoint set within the shouldContinueAfterSelecting callback at the NSLog and print out the relevant variables, this is what I will see:

(lldb) po multiEmail
ABMultiValueRef 0x17737ca0 with 8 value(s)
    0: null (0x3b864a60) - [email protected] (0x15d4bd30)
    1: null (0x3b864a60) - [email protected] (0x15f0f2d0)
    2: null (0x3b864a60) - [email protected] (0x15f3b470)
    3: null (0x3b864a60) - [email protected] (0x15d02060)
    4: _$!<Work>!$_ (0x15f352d0) - [email protected] (0x15f3d480)
    5: _$!<Other>!$_ (0x15fbeae0) - [email protected] (0x15f2a170)
    6: _$!<Other>!$_ (0x15de9ce0) - [email protected] (0x15f0f0e0)
    7: _$!<Other>!$_ (0x15f0a110) - [email protected] (0x15f00830)

(lldb) po selectedIndex
2

(lldb) po identifier
2

(lldb) po selectedEmail
[email protected]

I'd really appreciate some help here.

1

There are 1 answers

0
Nic Wise On

Sadly, this isn't the answer you are looking for.

I had this problem, but with phone numbers, not email. Same problem tho.

I "fixed" it by disabling contacts (both accounts - gmail and icloud) and then turning them back on again. Once that happened, and they had a little time to re-link, it worked fine.

I think it was a corrupted address book, but of course there is no evidence :(