API for selecting a contact in iOS seems unnecessarily difficult, it becomes a nightmare when you have to use it again and again at different places in your project. I think the idea of delegates is over-used in iOS, and they could have made things much simpler by relying on blocks instead.
So here again, instead of creating delegates again and again, I created a simple wrapper class that encapsulates the ugliness of the API and offers a clean way to the end developer. Here is how I use it in a view controller:
ETPeoplePicker *picker = [[ETPeoplePicker alloc] initWithViewController:self andSuccessBlock:^(NSString *name, NSString *number) { NSLog(@"You selected %@", number); } andFailureBlock:^ { }]; [picker show];
That’s it. Here is the code for ETPeoplePicker:
// // ETPeoplePicker.h // // Created by Umar Ashfaq on 5/16/14. // #import <Foundation/Foundation.h> #import <AddressBookUI/AddressBookUI.h> typedef void(^ETPeoplePickerSuccessBlock)(NSString *name, NSString *number); typedef void(^ETPeoplePickerFailureBlock)(); @interface ETPeoplePicker : UIView<ABPeoplePickerNavigationControllerDelegate> -(id)initWithViewController:(UIViewController *)viewController andSuccessBlock:(ETPeoplePickerSuccessBlock)success andFailureBlock:(ETPeoplePickerFailureBlock)failure; -(void) show; @end // // ETPeoplePicker.m // // Created by Umar Ashfaq on 5/16/14. // #import "ETPeoplePicker.h" #import "ETUtils.h" #import <AddressBookUI/AddressBookUI.h> #import "ETSentItemPreviewViewController.h" @interface ETPeoplePicker() <ABPeoplePickerNavigationControllerDelegate> @property(nonatomic, strong) ETPeoplePickerSuccessBlock success; @property(nonatomic, strong) ETPeoplePickerFailureBlock failure; @property(nonatomic, strong) UIViewController* viewController; @end @implementation ETPeoplePicker -(id)initWithViewController:(UIViewController *)viewController andSuccessBlock:(ETPeoplePickerSuccessBlock)success andFailureBlock:(ETPeoplePickerFailureBlock)failure { self = [super init]; if ( self ) { _viewController = viewController; _success = success; _failure = failure; } return self; } -(void) show { ABPeoplePickerNavigationController *abPicker = [[ABPeoplePickerNavigationController alloc] init]; abPicker.peoplePickerDelegate = self; abPicker.delegate = (ETSentItemPreviewViewController *) self.viewController; [self.viewController presentViewController:abPicker animated:NO completion:nil]; } - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person { [peoplePicker dismissViewControllerAnimated:NO completion:nil]; // recipient = person; NSString *recipientName = (__bridge NSString *)(ABRecordCopyCompositeName(person)); NSString *recipientPhone; // recipientPhone = (__bridge NSString *)(ABRecordCopyValue(person, kABPersonPhoneProperty)); ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); if ( ABMultiValueGetCount(phoneNumbers) > 0 ) { recipientPhone = (__bridge NSString *)(ABMultiValueCopyValueAtIndex(phoneNumbers, 0)); recipientPhone = [ETUtils normalizePhoneNumber:recipientPhone]; } CFRelease(phoneNumbers); NSLog(@"Selected number: %@", recipientPhone); self.success(recipientName, recipientPhone); return NO; } - (BOOL)peoplePickerNavigationController:(ABPeoplePickerNavigationController *)peoplePicker shouldContinueAfterSelectingPerson:(ABRecordRef)person property:(ABPropertyID)property identifier:(ABMultiValueIdentifier)identifier { [peoplePicker dismissViewControllerAnimated:YES completion:nil]; return NO; } - (void)peoplePickerNavigationControllerDidCancel:(ABPeoplePickerNavigationController *)peoplePicker { [peoplePicker dismissViewControllerAnimated:YES completion:nil]; } @end