How to tell ABPeoplePickerNavigationController to list only contacts that have an email address?
Asked Answered
E

2

6

I want my users to fill an email field by selecting a contact's email from their address books. I don't want them to scroll all the contacts whose emails are not set, so I want to filter the ones that have email addresses.

This is the code I've written so far. I can figure out who has an email address and who has not but I couldn't tell the ABPeoplePickerNavigationController to list only the right contacts. Is it impossible to achieve this, I mean do I have to implement my own contact picker class by using a table view or is there something wrong with this piece of code?

ABAddressBookRef addressBook = ABAddressBookCreate();
NSArray *peopleList = (NSArray *)ABAddressBookCopyArrayOfAllPeople(addressBook);
NSLog(@"%ld people exist in the addressBook", ABAddressBookGetPersonCount(addressBook));
for (id peopleRecord in peopleList) {
    ABMultiValueRef mv = ABRecordCopyValue((ABRecordRef)peopleRecord, kABPersonEmailProperty);
    CFIndex numberOfAddresses = ABMultiValueGetCount(mv);
    if(numberOfAddresses == 0) {
        CFErrorRef err;
        ABAddressBookRemoveRecord( addressBook, (ABRecordRef)peopleRecord, &err);
    }
}
[peopleList release];

NSLog(@"%ld people have an email", ABAddressBookGetPersonCount(addressBook));

ABPeoplePickerNavigationController *peoplePicker = [[ABPeoplePickerNavigationController alloc] init];
NSNumber* emailProp = [NSNumber numberWithInt:kABPersonEmailProperty];
[peoplePicker setAddressBook:addressBook];
peoplePicker.displayedProperties = [NSArray arrayWithObject:emailProp];
[peoplePicker setPeoplePickerDelegate:self];
[self presentModalViewController:peoplePicker animated:YES];
Emlyn answered 22/9, 2012 at 15:54 Comment(0)
U
1

I do not believe there is a way to get iOS to do this filtering. I do it in code too. Note that you need to look for all kinds of email addresses - you have to iterate through the dictionary that you can get. Working with this is a PITA for sure - I've done it before - and you have to be careful to not have memory leaks.

What I do is as you suggest - iterate through all contact myself, then I pop a view with a table and let then select the names of the people they want. I keep an association around so I know what address is associated with what name, then use the system email framework and then populate the send-to addresses.

Urinate answered 22/9, 2012 at 22:24 Comment(0)
I
15

I know this is old, but I stumbled across this while researching a related topic, so I thought I'd update this with my findings.

  1. While it doesn't filter the results, it's worth noting that iOS 8 has a feature for disabling contacts that don't have an email address:

    peoplePickerController.predicateForEnablingPerson = [NSPredicate predicateWithFormat:@"emailAddresses.@count > 0"];
    

    You still see all of the contacts, but at least those without an email address are disabled. Obviously, if your minimum target OS predates iOS 8, you'd do the above conditionally:

    if ([peoplePickerController respondsToSelector:@selector(predicateForEnablingPerson)]) {
        peoplePickerController.predicateForEnablingPerson = [NSPredicate predicateWithFormat:@"emailAddresses.@count > 0"];
    }
    
  2. If you want to filter out those entries without addresses, you'll have to present your own UI (e.g. create your own tableview) for this. So, first, build your own array of contacts with email addresses like so:

    ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
        if (granted) {
            NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook));
            NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(id person, NSDictionary *bindings) {
                ABMultiValueRef emails = ABRecordCopyValue((__bridge ABRecordRef)person, kABPersonEmailProperty);
                NSInteger count = ABMultiValueGetCount(emails);
                CFRelease(emails);
                return count > 0;
            }];
    
            NSArray *peopleWithEmails = [allPeople filteredArrayUsingPredicate:predicate];
    
            // You now have an array of `ABRecordRef` associated with 
            // those contacts with email addresses. You can use this as 
            // the model backing your own table view, or populate your
            // own model.
        } else {
            NSLog(@"Access not granted");
            if (error) {
                CFRelease(error);
            }
        }
    });
    

    Having done that, you can then build your own tableview listing the relevant details from that peopleWithEmails.

Ipecac answered 11/8, 2014 at 23:30 Comment(1)
Note, the code under point 2 is for iOS 6 and later. If you need support for earlier iOS versions, you don't check for permission with ABAddressBookRequestAccessWithCompletion.Ipecac
U
1

I do not believe there is a way to get iOS to do this filtering. I do it in code too. Note that you need to look for all kinds of email addresses - you have to iterate through the dictionary that you can get. Working with this is a PITA for sure - I've done it before - and you have to be careful to not have memory leaks.

What I do is as you suggest - iterate through all contact myself, then I pop a view with a table and let then select the names of the people they want. I keep an association around so I know what address is associated with what name, then use the system email framework and then populate the send-to addresses.

Urinate answered 22/9, 2012 at 22:24 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.