Extract email from CNContactProperty - iOS 9
Asked Answered
M

5

7

I have an iOS app which needs access to the Contacts picker view controller in order to allow the user to select a contact property such as email address/ telephone numbers of imessage email addresses.

The problem I am having right now, is that I can't figure out how to parse the returned data. I have made use of the contactPicker didSelectContactProperty method, but I am unable to parse the data I need.

-(void)contactPicker:(CNContactPickerViewController *)picker didSelectContactProperty:(CNContactProperty *)contactProperty {

   CNLabeledValue *test = contactProperty.contact.emailAddresses.firstObject;
   NSLog(@"%@", test);

   NSLog(@"%@", contactProperty.contact.phoneNumbers);
}

If you run the above code you get the following response:

2015-10-11 13:30:07.059 Actions[516:212765] <CNLabeledValue: 0x13656d090: identifier=21F2B1B2-8158-466B-9224-E2036CA07D28, label=_$!<Other>!$_, [email protected]> 2015-10-11 13:30:07.061 App_Name[516:212765] (
    "<CNLabeledValue: 0x13672a500: identifier=6697A0E9-3B91-4566-B26E-83B87979F816, label=_$!<Main>!$_, value=<CNPhoneNumber: 0x13672a660: countryCode=gb, digits=08000391010>>" )

Thats great, but how do I extract the data I need from it? Why are the NSLog statements returning the data in a weird format?

Thanks for your time, Dan.

Monongahela answered 11/10, 2015 at 12:32 Comment(0)
W
15

The returned values are of the CNLabeledValue class. In order to get the value from them, for, say, the emails, do this

CNLabeledValue *emailValue = contactProperty.contact.emailAddresses.firstObject;
NSString *emailString = emailValue.value;

If the value you wanted a phone number, this is how you would retrieve that

CNLabeledValue *phoneNumberValue = contactProperty.contact.phoneNumbers.firstObject;
CNPhoneNumber *phoneNumber = phoneNumberValue.value;
NSString *phoneNumberString = phoneNumber.stringValue;

Because the returned value is a CNLabeledValue, you are also able to retrieve the phone number's or email's label

NSString *emailLabel = emailValue.label; //This may be 'Work', 'Home', etc.
NSString *phoneNumberLabel = phoneNumberValue.label;
Wrong answered 11/10, 2015 at 12:51 Comment(11)
Ah right I see. Thanks so much. I have just upgraded from using the older AddressBook framework, so I was struggling with this. Thanks again :)Monongahela
Just one question, I am expecting the user to select either an email address of a telephone number. How can I check what they have selected?Monongahela
I think that that information would be stored in contactProperty.value, contactProperty.label, contactProperty.key, etc. I would test each of those and see what it outputs, as I've never used this before personally.Wrong
Awesome, contactProperty.key works perfectly. Thanks Chris :)Monongahela
I promise this will be my last question, but do you know if there is some sort of indexPath.row number I can use? (Instead of emailAddresses.firstObject). So I could do emailAddresses[indexPath.row].Monongahela
If you mean that you need the index of the selected email address, I believe that contactProperty.value points to the email and that, as a result, you don't need to use the emailAddresses array.Wrong
Ah right I see. Brilliant, I promise I wont pester you anymore. Thanks :)Monongahela
Hey @ChrisLoonam, when I try to get the label of CNLabeledValueI get a text like this : "$!<Home>!$"Wini
yes, i got this result, but i want to get only work email, not other email like home and etc.Counterweight
To get properly localized labels instead of strings like "$!<Home>!$", use this code: [CNLabeledValue localizedStringForLabel:[phoneNumberValue label]];Fourdimensional
Would this still work if you've got multiple addresses and the user has selected anything other than the first address?Cubature
L
2

Swift

This is the proper way how to do it:

func contactPicker(_ picker: CNContactPickerViewController, didSelect contactProperty: CNContactProperty) {
    if contactProperty.key == CNContactEmailAddressesKey,
       let emailAddress = contactProperty.value as? String
    {
        print(emailAddress)
    }
}

If you would select contactProperty.contact.emailAddresses.first, you would get the first email address of the contact which might not necessary be the email address the user has selected.

In case you are querying phone numbers, use the following body instead:

if let phoneNumber = contactProperty.value as? CNPhoneNumber {
    print(phoneNumber.stringValue)
}
Laryngitis answered 18/11, 2022 at 18:23 Comment(0)
U
1

For swift 3.0 :

 public func contactPicker(_ picker: CNContactPickerViewController, didSelect contact: CNContact)
{
      if let emailValue : CNLabeledValue = contact.emailAddresses.first
    {
        txtEmail.text = emailValue.value as String
    }
    if let phoneNumber : CNLabeledValue = contact.phoneNumbers.first
    {
        txtMobno.text = phoneNumber.value.stringValue
    }
     txtFname.text = contact.givenName + " " + contact.familyName

}
Unheardof answered 5/12, 2016 at 12:21 Comment(0)
C
1

Unfortunately Chris' answer tells you how to get the value from the CNLabeledValue object that is returned, but it doesn't tell you how to identify what CNLabeledValue was selected based on the contactProperty parameter the function features.

What you need to do is cycle through each of the contact's email addresses and check if it's identifier matches up with the selected contactProperty identifier. Use the following code inside the didSelectContactProperty function:

NSString *selectedEmail;

for (CNLabeledValue<NSString*>* email in contactProperty.contact.emailAddresses) {
    if ([email.identifier isEqualToString:contactProperty.identifier]) {
            selectedEmail = (NSString *)email.value;
    }
}

Note I have only tested this code with postal addresses, so it may require some further tweaking to work with email addresses.

Cubature answered 5/9, 2018 at 10:7 Comment(0)
U
0
Here is swift version of Chris answer :

 func fatchContacts(store : CNContactStore)  {
    do
    {
    let groups = try store.groups(matching: nil)
    let predicate =  CNContact.predicateForContactsInGroup(withIdentifier: groups[0].identifier)
    //let predicate = CNContact.predicateForContactsMatchingName("John")
        let keyToFatch = [CNContactFormatter.descriptorForRequiredKeys(for: .fullName ) ,CNContactEmailAddressesKey] as [Any]
    let contacts = try store.unifiedContacts(matching: predicate, keysToFetch: keyToFatch as! [CNKeyDescriptor])            //------------------------------------------------------
   //-------------Get Here-----------------------------------------
     print(contacts)
     print(contacts[0])
        let formatter = CNContactFormatter ()
        print(formatter.string(from: contacts[0]))
        print(contacts[0].givenName)
        print(contacts[0].emailAddresses)
        let emailValue : CNLabeledValue = contacts[0].emailAddresses.first!;
        let  email = emailValue.value
        print(email)




    }
    catch{

    }
}


Just pass the CNContactStore object        
Unheardof answered 25/11, 2016 at 14:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.