4

I am trying to get selected mobile phone number with

ABMultiValueRef phones = ABRecordCopyValue(person, property);
CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, identifier);

I have a contact with several mobile phones (all labeled 'mobile'). When I select the first one, phoneNumber gives me the first one, but if I select any consecutive one, phoneNumber gives me the previous number:

Contact: Jay Jaymes mobile +1111111111 mobile +2222222222 mobile +3333333333

Tap first one, phoneNumber = +1111111111

Tap second one, phoneNumber = +1111111111

Tap third one, phoneNumber = +2222222222

Rob
  • 415,655
  • 72
  • 787
  • 1,044

4 Answers4

4

This is code I use. And It will give correct phone number only

  - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier {

        if (property == kABPersonPhoneProperty) {

            ABMultiValueRef phoneProperty = ABRecordCopyValue(person,property);
            CFIndex peopleIndex = ABMultiValueGetIndexForIdentifier(property, identifier);
            NSString *phone = (__bridge_transfer NSString*)ABMultiValueCopyValueAtIndex(phoneProperty, peopleIndex);

            [self dismissModalViewControllerAnimated:YES];
        }
    return NO;
}
Bhumeshwer katre
  • 4,671
  • 2
  • 19
  • 29
  • That's exactly what I am doing. Except __bridge_transfer I am using just __bridge, but I doubt that changes anything. It started working as expected (at least on simulator) – user3003787 Nov 22 '13 at 11:31
  • 1
    @user3003787 If use `__bridge_transfer`, ARC will take care of releasing this object for you. If you use `__bridge`, you'll have to manually `CFRelease` the object or else you'll leak. If you run your code through the static analyzer ("Analyze" on Xcode's "Product" menu), it's pretty good at identifying these sorts of issues for you. – Rob Sep 11 '14 at 03:09
  • @Rob This is just sample how to retrieve phone number. There are may lot of case in which number is wrong. In this case you can put some `Regular expression` to check that. – Bhumeshwer katre Sep 11 '14 at 05:24
  • 1
    I made changes in answer, may be others should not misguide. Thanks @Rob for noticing this. – Bhumeshwer katre Sep 11 '14 at 12:13
0

You can easily iterate like that. Try NSLoging that code to make sure it works. I think you have some bugs in your "choosing" logic.

ABMultiValueRef phones = ABRecordCopyValue(person, kABPersonPhoneProperty);

for (CFIndex i=0; i < ABMultiValueGetCount(phones); i++) 
{
   NSString* phoneLabel = (NSString*)ABMultiValueCopyLabelAtIndex(phones, i);
   NSString* phoneNumber = ABMultiValueCopyValueAtIndex(phones, i);

   //release variables since you were using COPY !!!
   CFRelease(phoneNumber);
   CFRelease(phoneLabel);
}

CFRelease(phones);
Grzegorz Krukowski
  • 18,081
  • 5
  • 50
  • 71
0

Ended up implementing it this way:

- (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier
{
   if (property == kABPersonPhoneProperty)
    {
        ABMultiValueRef phones = ABRecordCopyValue(person, property);
        CFStringRef phoneNumber = ABMultiValueCopyValueAtIndex(phones, identifier);
        NSLog(@"%@", phoneNumber);
        NSMutableString *tmp = [NSMutableString stringWithFormat:@"%@", (__bridge_transfer NSString *)phoneNumber];
        NSString *strippedPhoneNumber = [tmp stringByReplacingOccurrencesOfString:@" " withString:@""];
        NSCharacterSet *doNotWant = [NSCharacterSet characterSetWithCharactersInString:@"()-"];
        strippedPhoneNumber = [[strippedPhoneNumber componentsSeparatedByCharactersInSet: doNotWant] componentsJoinedByString: @""];
        NSString *firstName = (__bridge_transfer NSString *)ABRecordCopyValue(person, kABPersonFirstNameProperty);
        [peoplePicker dismissViewControllerAnimated:YES completion:nil];
        return NO;
}
  • Two problems: First, you should not use `identifier` in `ABMultiValueCopyValueAtIndex`. You should first get an index from the `identifier` using `ABMultiValueGetIndexForIdentifier`, and then use that `CFIndex` in `ABMultiValueCopyValueAtIndex`. Second, you're not performing the `CFRelease(phones)`, so this will leak. Run this thru the static analyzer ("Analyze" on Xcode "Product" menu) and it's pretty good at identifying these issues. – Rob Sep 11 '14 at 15:43
0

You should not be using the identifier as the index within ABMultiValueCopyValueAtIndex. You should call ABMultiValueGetIndexForIdentifier to convert the ABMultiValueIdentifier identifier into a CFIndex index:

ABMultiValueRef phones = ABRecordCopyValue(person, property);
CFIndex index = ABMultiValueGetIndexForIdentifier(phones, identifier);
NSString *phoneNumber = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phones, index));
CFRelease(phones);

Generally, the ABMultiValueIdentifier values match the CFIndex values retrieved by ABMultiValueGetIndexForIdentifier, but if a contact was edited (specifically if one of the earlier phone numbers was deleted), using the ABMultiValueIdentifier in ABMultiValueCopyValueAtIndex will return the wrong record.

Rob
  • 415,655
  • 72
  • 787
  • 1,044