├── README.md ├── WCSContactPicker ├── Contact.h ├── Contact.m ├── ContactCell.h ├── ContactCell.m ├── ContactCell.xib ├── WCSContactPicker.h └── WCSContactPicker.m ├── WCSContacts.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcuserdata │ └── Aaron.xcuserdatad │ └── xcschemes │ ├── WCSContacts.xcscheme │ └── xcschememanagement.plist ├── WCSContacts ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ └── contact-image-none.imageset │ │ ├── Contents.json │ │ ├── contact-image-none-1.png │ │ └── contact-image-none.png ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m └── main.m └── screens ├── screen-1.png ├── screen-2.png └── screen-3.png /README.md: -------------------------------------------------------------------------------- 1 | WCSContactPicker 2 | =========== 3 | 4 | iOS 9 Contact picker — Apples replacement for the AddressBook framework. 5 | 6 | ![enter image description here](https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/master/screens/screen-1.png) ![enter image description here](https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/master/screens/screen-2.png) ![enter image description here](https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/master/screens/screen-3.png) 7 | 8 | Requirements 9 | ------------ 10 | 11 | Requires **iOS 9,** the `ContactsUI.framework` and `Contacts.framework`. 12 | 13 | 14 | Usage 15 | ------------ 16 | 17 | 1. Include `WCSContactPicker` in your project and import the header file. 18 | 2. Create an instance of `WCSContactPicker` and present a navigation controller. 19 | 3. Receive delegate call back with a `Contact` object. 20 | 21 | > #import "WCSContactPicker.h" 22 | > @interface ViewController () 23 | > @end 24 | > 25 | > WCSContactPicker * _picker = [[WCSContactPicker alloc] initWithDelegate:self]; 26 | > UINavigationController * controller = [[UINavigationController alloc] initWithRootViewController:_picker]; 27 | > [self presentViewController:controller animated:YES completion:NULL]; 28 | 29 | Delegate 30 | ------------ 31 | 32 | Use the delegate callbacks for receive information about authorization, get a generic `Contact` object or be informed if the user simply cancels Contact selection. 33 | 34 | ```objc 35 | - (void)picker:(WCSContactPicker*)picker didSelectContact:(Contact*)contact; 36 | - (void)picker:(WCSContactPicker*)picker didFailToAccessContacts:(NSError*)error; 37 | - (void)didCancelContactSelection; 38 | ``` 39 | 40 | Contact Object 41 | ------------ 42 | 43 | This object contains simple to access basic Contact information from `CNContact` such as the First, Last, Nick, Phones, Email, Urls, etc. 44 | 45 | @WrightsCS 46 | ------------ 47 | 48 | Comments and feedback are welcome. Let me know if you contribute, find any bugs, have suggestions, etc. 49 | Twitter: @WrightsCS 50 | http://www.wrightscsapps.com 51 | 52 | Apps using WCSContactPicker 53 | ------------ 54 | 55 | If you are using this in your app, please let me know and I will add your app here! 56 | -------------------------------------------------------------------------------- /WCSContactPicker/Contact.h: -------------------------------------------------------------------------------- 1 | // 2 | // People.h 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | @import UIKit; 13 | #import 14 | 15 | NS_ASSUME_NONNULL_BEGIN 16 | 17 | @interface Contact : NSObject 18 | 19 | @property (nonnull, strong, nonatomic) NSString * displayName; 20 | @property (nonnull, strong, nonatomic) NSString * detailText; 21 | 22 | @property (nonnull, strong, nonatomic) NSString * firstname; 23 | @property (nonnull, strong, nonatomic) NSString * nickname; 24 | @property (nonnull, strong, nonatomic) NSString * lastname; 25 | 26 | @property (nonnull, strong, nonatomic) NSString * street1; 27 | @property (nonnull, strong, nonatomic) NSString * street2; 28 | @property (nonnull, strong, nonatomic) NSString * city; 29 | @property (nonnull, strong, nonatomic) NSString * state; 30 | @property (nonnull, strong, nonatomic) NSString * zip; 31 | @property (nonnull, strong, nonatomic) NSString * country; 32 | 33 | @property (nonnull, strong, nonatomic) NSString * company; 34 | @property (nonnull, strong, nonatomic) NSArray * urls; 35 | 36 | @property (nonnull, strong, nonatomic) NSDate * birthday; 37 | 38 | @property (nonnull, strong, nonatomic) NSArray * address; 39 | @property (nonnull, strong, nonatomic) NSArray * phones; 40 | @property (nonnull, strong, nonatomic) NSArray * emails; 41 | 42 | @property (nonnull, strong, nonatomic) UIImage * photo; 43 | @property (nonnull, strong, nonatomic) UIImage * thumb; 44 | 45 | - (NSString*)addressString; 46 | 47 | @end 48 | 49 | NS_ASSUME_NONNULL_END 50 | -------------------------------------------------------------------------------- /WCSContactPicker/Contact.m: -------------------------------------------------------------------------------- 1 | // 2 | // People.m 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import "Contact.h" 13 | 14 | @implementation Contact 15 | 16 | - (NSString*)addressString { 17 | return [NSString stringWithFormat:@"%@ %@, %@ %@ %@", 18 | _street1, 19 | _city, 20 | _state, 21 | _zip, 22 | _country 23 | ]; 24 | } 25 | 26 | - (NSString*)description { 27 | return [NSString stringWithFormat:@"first=%@, nickname=%@, last=%@, birthday=%@, company=%@, phones=%@, emails:%@, urls=%@, address=(%@)", 28 | _firstname, 29 | _nickname, 30 | _lastname, 31 | _birthday, 32 | _company, 33 | _phones, 34 | _emails, 35 | _urls, 36 | [self addressString] 37 | ]; 38 | } 39 | 40 | - (NSString*)displayName { 41 | if ( self.firstname != nil && self.lastname != nil && ![self.firstname isEqualToString:@""] && ![self.lastname isEqualToString:@""] ) 42 | return [NSString stringWithFormat:@"%@ %@", self.firstname, self.lastname]; 43 | if ( self.firstname != nil && ![self.firstname isEqualToString:@""] ) 44 | return [NSString stringWithFormat:@"%@", self.firstname]; 45 | if ( self.lastname != nil && ![self.lastname isEqualToString:@""] ) 46 | return [NSString stringWithFormat:@"%@", self.lastname]; 47 | else if ( self.nickname != nil && ![self.nickname isEqualToString:@""] ) 48 | return [NSString stringWithFormat:@"%@", self.nickname]; 49 | else if ( self.company != nil && ![self.company isEqualToString:@""] ) 50 | return [NSString stringWithFormat:@"%@", self.company]; 51 | else if ( self.phones.count ) 52 | return [NSString stringWithFormat:@"%@", self.phones[0]]; 53 | else if ( self.emails.count ) 54 | return [NSString stringWithFormat:@"%@", self.emails[0]]; 55 | return @"No name"; 56 | } 57 | - (NSString *)detailText { 58 | if ( self.phones.count ) 59 | return [NSString stringWithFormat:@"phone: %@", self.phones[0]]; 60 | else if ( self.emails.count ) 61 | return [NSString stringWithFormat:@"email: %@", self.emails[0]]; 62 | else if ( self.company.length != 0 ) 63 | return [NSString stringWithFormat:@"company: %@", self.company]; 64 | else if ( self.nickname.length != 0 ) 65 | return [NSString stringWithFormat:@"nickname: %@", self.nickname]; 66 | return @"No details"; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /WCSContactPicker/ContactCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ContactCell.h 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import 13 | 14 | @interface ContactCell : UITableViewCell 15 | 16 | @property (strong, nonatomic) UIImage * thumbnail; 17 | @property (strong, nonatomic) NSString * displayName; 18 | @property (strong, nonatomic) NSString * phoneNumber; 19 | @property (strong, nonatomic) NSString * emailAddress; 20 | 21 | @end 22 | -------------------------------------------------------------------------------- /WCSContactPicker/ContactCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ContactCell.m 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import "ContactCell.h" 13 | 14 | @interface ContactCell () 15 | @property (nonatomic, weak) IBOutlet UIImageView * imageThumbnail; 16 | @property (nonatomic, weak) IBOutlet UILabel * labelDisplayName, * labelPhoneNumber, * labelEmailAddress; 17 | 18 | @end 19 | 20 | @implementation ContactCell 21 | 22 | - (void)awakeFromNib 23 | { 24 | _labelDisplayName.textColor = [UIColor blackColor]; 25 | _labelPhoneNumber.textColor = [UIColor grayColor]; 26 | _labelEmailAddress.textColor = [UIColor lightGrayColor]; 27 | } 28 | 29 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 30 | [super setSelected:selected animated:animated]; 31 | // Configure the view for the selected state 32 | } 33 | 34 | #pragma mark - Private Methods 35 | 36 | - (void)setThumbnail:(UIImage *)thumbnail { 37 | _imageThumbnail.image = thumbnail; 38 | } 39 | 40 | - (void)setDisplayName:(NSString *)displayName { 41 | _labelDisplayName.text = displayName; 42 | } 43 | 44 | - (void)setPhoneNumber:(NSString *)phoneNumber { 45 | _labelPhoneNumber.text = phoneNumber; 46 | } 47 | 48 | - (void)setEmailAddress:(NSString *)emailAddress { 49 | _labelEmailAddress.text = emailAddress; 50 | } 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /WCSContactPicker/ContactCell.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 23 | 30 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /WCSContactPicker/WCSContactPicker.h: -------------------------------------------------------------------------------- 1 | // 2 | // WCSContactPicker.h 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | @import Contacts; 13 | @import ContactsUI; 14 | #import 15 | #import "Contact.h" 16 | 17 | @class WCSContactPicker; 18 | 19 | @protocol WCSContactPickerDelegate 20 | @optional 21 | - (void)picker:(nullable WCSContactPicker*)picker didSelectContact:(nonnull Contact*)contact; 22 | - (void)picker:(nullable WCSContactPicker*)picker didFailToAccessContacts:(nullable NSError*)error; 23 | - (void)didCancelContactSelection; 24 | @end 25 | 26 | @interface WCSContactPicker : UITableViewController 27 | - (instancetype _Nonnull)initWithDelegate:(id _Nullable) delegate; 28 | @property (nullable, assign, nonatomic) id delegate; 29 | @end 30 | -------------------------------------------------------------------------------- /WCSContactPicker/WCSContactPicker.m: -------------------------------------------------------------------------------- 1 | // 2 | // WCSContactPicker.m 3 | // WCSContactPicker - iOS 9 Contacts 4 | // 5 | // Created by Aaron C. Wright on 8/31/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import "ContactCell.h" 13 | #import "WCSContactPicker.h" 14 | 15 | @interface WCSContactPicker () { 16 | CNContactStore * _contactStore; 17 | } 18 | @property (assign) BOOL contactsError; 19 | @property (nonatomic, strong) NSArray * contacts; 20 | @end 21 | 22 | @implementation WCSContactPicker 23 | 24 | - (instancetype _Nonnull)initWithDelegate:(id _Nullable)delegate { 25 | self = [super initWithStyle:UITableViewStylePlain]; 26 | if ( self ) { 27 | _delegate = delegate; 28 | } 29 | return self; 30 | } 31 | 32 | - (void)viewDidLoad { 33 | [super viewDidLoad]; 34 | 35 | self.title = NSLocalizedString(@"Contacts", nil); 36 | self.navigationItem.leftBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancel:)]; 37 | } 38 | 39 | - (void)viewWillAppear:(BOOL)animated 40 | { 41 | [super viewWillAppear:animated]; 42 | [self reloadContacts]; 43 | } 44 | 45 | - (void)didReceiveMemoryWarning { 46 | [super didReceiveMemoryWarning]; 47 | // Dispose of any resources that can be recreated. 48 | } 49 | 50 | #pragma mark - Private Methods 51 | 52 | - (void)reloadContacts 53 | { 54 | [self getContacts:^(NSArray *contacts, NSError *error) { 55 | _contacts = contacts; 56 | _contactsError = error != nil ? YES : NO; 57 | [self.tableView reloadData]; 58 | }]; 59 | } 60 | 61 | - (void)getContacts:(void (^)(NSArray * contacts, NSError * error))completion 62 | { 63 | if ( !_contactStore ) 64 | _contactStore = [[CNContactStore alloc] init]; 65 | 66 | NSError * _contactError = [NSError errorWithDomain:@"WCSContactsErrorDomain" code:1 userInfo:@{NSLocalizedDescriptionKey:@"Not authorized to access Contacts."}]; 67 | 68 | switch ( [CNContactStore authorizationStatusForEntityType:CNEntityTypeContacts] ) 69 | { 70 | case CNAuthorizationStatusDenied: 71 | case CNAuthorizationStatusRestricted: { 72 | if ( [self.delegate respondsToSelector:@selector(picker:didFailToAccessContacts:)] ) 73 | [self.delegate picker:self didFailToAccessContacts:_contactError]; 74 | completion(nil, _contactError); 75 | break; 76 | } 77 | case CNAuthorizationStatusNotDetermined: 78 | { 79 | [_contactStore requestAccessForEntityType:CNEntityTypeContacts 80 | completionHandler:^(BOOL granted, NSError * _Nullable error) { 81 | if ( ! granted ) { 82 | dispatch_async(dispatch_get_main_queue(), ^{ 83 | completion(nil, _contactError); 84 | }); 85 | } 86 | else 87 | [self getContacts:completion]; 88 | }]; 89 | break; 90 | } 91 | 92 | case CNAuthorizationStatusAuthorized: 93 | { 94 | NSMutableArray * _contactsTemp = [NSMutableArray new]; 95 | CNContactFetchRequest * _contactRequest = [[CNContactFetchRequest alloc] initWithKeysToFetch:[self contactKeys]]; 96 | [_contactStore enumerateContactsWithFetchRequest:_contactRequest error:nil usingBlock:^(CNContact * _Nonnull contact, BOOL * _Nonnull stop) { 97 | [_contactsTemp addObject:contact]; 98 | }]; 99 | dispatch_async(dispatch_get_main_queue(), ^{ 100 | completion(_contactsTemp, nil); 101 | }); 102 | break; 103 | } 104 | } 105 | } 106 | 107 | - (UIImage*)contactImage:(UIImage*)original 108 | { 109 | if ( original == nil ) 110 | original = [UIImage imageNamed:@"contact-image-none"]; 111 | 112 | UIGraphicsBeginImageContextWithOptions(CGSizeMake(60, 60), NO, [UIScreen mainScreen].scale); 113 | 114 | UIBezierPath* clipPath = [UIBezierPath bezierPathWithOvalInRect:CGRectInset(CGRectMake(0, 0, 60, 60), 0.5,0.5)]; 115 | [clipPath addClip]; 116 | 117 | [original drawInRect:CGRectMake(0, 0, 60, 60)]; 118 | 119 | UIImage * renderedImage = UIGraphicsGetImageFromCurrentImageContext(); 120 | UIGraphicsEndImageContext(); 121 | 122 | return renderedImage; 123 | } 124 | 125 | - (Contact*)personFromContact:(CNContact*)contact 126 | { 127 | Contact * _contact = [Contact new]; 128 | /* 129 | !$_, value=>", 131 | "!$_, value=>" 132 | ), emailAddresses=( 133 | "!$_, value=John-Appleseed@mac.com>" 134 | ), postalAddresses=( 135 | "!$_, value=>", 136 | "!$_, value=>" 137 | )> 138 | */ 139 | _contact.photo = [self contactImage:[UIImage imageWithData:contact.imageData]]; 140 | _contact.thumb = [self contactImage:[UIImage imageWithData:contact.thumbnailImageData]]; 141 | _contact.firstname = contact.givenName; 142 | _contact.lastname = contact.familyName; 143 | _contact.nickname = contact.nickname; 144 | _contact.company = contact.organizationName; 145 | _contact.birthday = contact.birthday != nil ? [[[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian] dateFromComponents:contact.birthday] : [NSDate date]; 146 | 147 | if ( contact.phoneNumbers.count ) 148 | { 149 | NSMutableArray * _tempPhones = [NSMutableArray new]; 150 | for ( CNLabeledValue * _contactPhone in contact.phoneNumbers ) { 151 | CNPhoneNumber * _phoneNumber = _contactPhone.value; 152 | [_tempPhones addObject:_phoneNumber.stringValue]; 153 | } 154 | _contact.phones = _tempPhones; 155 | } 156 | 157 | if ( contact.emailAddresses.count ) 158 | { 159 | NSMutableArray * _tempEmails = [NSMutableArray new]; 160 | for ( CNLabeledValue * _contactEmail in contact.emailAddresses ) 161 | [_tempEmails addObject:_contactEmail.value]; 162 | _contact.emails = _tempEmails; 163 | } 164 | 165 | if ( contact.postalAddresses.count ) 166 | { 167 | CNLabeledValue * _contactAddress = contact.postalAddresses[0]; 168 | CNPostalAddress * _address = _contactAddress.value; 169 | _contact.street1 = _address.street; 170 | _contact.city = _address.city; 171 | _contact.state = _address.state; 172 | _contact.zip = _address.postalCode; 173 | _contact.country = _address.country; 174 | } 175 | 176 | if ( contact.urlAddresses.count ) 177 | { 178 | NSMutableArray * _tempUrls = [NSMutableArray new]; 179 | for ( CNLabeledValue * _contactUrl in contact.urlAddresses ) 180 | [_tempUrls addObject:_contactUrl.value]; 181 | _contact.urls = _tempUrls; 182 | } 183 | 184 | return _contact; 185 | } 186 | 187 | - (NSArray*)contactKeys 188 | { 189 | return @[CNContactNamePrefixKey, 190 | CNContactGivenNameKey, 191 | CNContactMiddleNameKey, 192 | CNContactFamilyNameKey, 193 | CNContactPreviousFamilyNameKey, 194 | CNContactNameSuffixKey, 195 | CNContactNicknameKey, 196 | CNContactPhoneticGivenNameKey, 197 | CNContactPhoneticMiddleNameKey, 198 | CNContactPhoneticFamilyNameKey, 199 | CNContactOrganizationNameKey, 200 | CNContactDepartmentNameKey, 201 | CNContactJobTitleKey, 202 | CNContactBirthdayKey, 203 | CNContactNonGregorianBirthdayKey, 204 | CNContactNoteKey, 205 | CNContactImageDataKey, 206 | CNContactThumbnailImageDataKey, 207 | CNContactImageDataAvailableKey, 208 | CNContactTypeKey, 209 | CNContactPhoneNumbersKey, 210 | CNContactEmailAddressesKey, 211 | CNContactPostalAddressesKey, 212 | CNContactDatesKey, 213 | CNContactUrlAddressesKey, 214 | CNContactRelationsKey, 215 | CNContactSocialProfilesKey, 216 | CNContactInstantMessageAddressesKey]; 217 | } 218 | 219 | #pragma mark IBActions 220 | 221 | - (IBAction)cancel:(id)sender { 222 | if ( [self.delegate respondsToSelector:@selector(didCancelContactSelection)] ) 223 | [self.delegate didCancelContactSelection]; 224 | [self.navigationController dismissViewControllerAnimated:YES completion:NULL]; 225 | } 226 | 227 | 228 | #pragma mark - Table view data source 229 | 230 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 231 | return 1; 232 | } 233 | 234 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 235 | return _contacts.count ? _contacts.count : 1; 236 | } 237 | 238 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 239 | return 75.f; 240 | } 241 | 242 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 243 | { 244 | if ( _contacts.count ) 245 | { 246 | static NSString *CellIdentifier = @"ContactCell"; 247 | ContactCell * cell = (ContactCell *)[tableView dequeueReusableCellWithIdentifier:CellIdentifier]; 248 | NSArray *nib = [[NSBundle mainBundle] loadNibNamed:CellIdentifier owner:self options:nil]; 249 | cell = [nib objectAtIndex:0]; 250 | 251 | Contact * _contact = [self personFromContact:(CNContact*)_contacts[indexPath.row]]; 252 | cell.thumbnail = _contact.thumb; 253 | cell.displayName = _contact.displayName; 254 | cell.phoneNumber = _contact.phones[0]; 255 | cell.emailAddress = _contact.emails[0]; 256 | 257 | return cell; 258 | } 259 | else 260 | { 261 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"CellIdentifier"]; 262 | if ( cell ) cell = nil; 263 | if ( ! cell ) { 264 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:@"CellIdentifier"]; 265 | cell.accessoryType = UITableViewCellAccessoryNone; 266 | } 267 | 268 | if ( _contactsError ) 269 | { 270 | cell.textLabel.text = NSLocalizedString(@"Contacts Error", nil); 271 | cell.detailTextLabel.numberOfLines = 2; 272 | cell.detailTextLabel.text = NSLocalizedString(@"Enable Contacts under iOS Settings -> Privacy -> Contacts.", nil); 273 | } 274 | else 275 | { 276 | cell.textLabel.text = NSLocalizedString(@"No Contacts", nil); 277 | cell.detailTextLabel.numberOfLines = 1; 278 | cell.detailTextLabel.text = NSLocalizedString(@"There are no Contacts available.", nil); 279 | } 280 | 281 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 282 | return cell; 283 | } 284 | 285 | return nil; 286 | } 287 | 288 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 289 | { 290 | if ( _contacts.count ) 291 | { 292 | if ( [self.delegate respondsToSelector:@selector(picker:didSelectContact:)] ) 293 | [self.delegate picker:self didSelectContact:[self personFromContact:(CNContact*)_contacts[indexPath.row]]]; 294 | [self dismissViewControllerAnimated:YES completion:NULL]; 295 | } 296 | else 297 | { 298 | if ( _contactsError ) { 299 | [[UIApplication sharedApplication] openURL:[NSURL URLWithString:UIApplicationOpenSettingsURLString]]; 300 | } 301 | } 302 | } 303 | 304 | @end 305 | -------------------------------------------------------------------------------- /WCSContacts.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 931E204C1BA795CE00C8E65B /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E204B1BA795CE00C8E65B /* main.m */; }; 11 | 931E204F1BA795CE00C8E65B /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E204E1BA795CE00C8E65B /* AppDelegate.m */; }; 12 | 931E20521BA795CE00C8E65B /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E20511BA795CE00C8E65B /* ViewController.m */; }; 13 | 931E20551BA795CE00C8E65B /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 931E20531BA795CE00C8E65B /* Main.storyboard */; }; 14 | 931E20571BA795CE00C8E65B /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 931E20561BA795CE00C8E65B /* Assets.xcassets */; }; 15 | 931E205A1BA795CE00C8E65B /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 931E20581BA795CE00C8E65B /* LaunchScreen.storyboard */; }; 16 | 931E20691BA795D700C8E65B /* Contact.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E20631BA795D700C8E65B /* Contact.m */; settings = {ASSET_TAGS = (); }; }; 17 | 931E206A1BA795D700C8E65B /* ContactCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E20651BA795D700C8E65B /* ContactCell.m */; settings = {ASSET_TAGS = (); }; }; 18 | 931E206B1BA795D700C8E65B /* ContactCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 931E20661BA795D700C8E65B /* ContactCell.xib */; settings = {ASSET_TAGS = (); }; }; 19 | 931E206C1BA795D700C8E65B /* WCSContactPicker.m in Sources */ = {isa = PBXBuildFile; fileRef = 931E20681BA795D700C8E65B /* WCSContactPicker.m */; settings = {ASSET_TAGS = (); }; }; 20 | /* End PBXBuildFile section */ 21 | 22 | /* Begin PBXFileReference section */ 23 | 931E20471BA795CE00C8E65B /* WCSContacts.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = WCSContacts.app; sourceTree = BUILT_PRODUCTS_DIR; }; 24 | 931E204B1BA795CE00C8E65B /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 25 | 931E204D1BA795CE00C8E65B /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = AppDelegate.h; path = WCSContacts/AppDelegate.h; sourceTree = ""; }; 26 | 931E204E1BA795CE00C8E65B /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = AppDelegate.m; path = WCSContacts/AppDelegate.m; sourceTree = ""; }; 27 | 931E20501BA795CE00C8E65B /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 28 | 931E20511BA795CE00C8E65B /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 29 | 931E20541BA795CE00C8E65B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 30 | 931E20561BA795CE00C8E65B /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; name = Assets.xcassets; path = WCSContacts/Assets.xcassets; sourceTree = ""; }; 31 | 931E20591BA795CE00C8E65B /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 32 | 931E205B1BA795CE00C8E65B /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; name = Info.plist; path = WCSContacts/Info.plist; sourceTree = ""; }; 33 | 931E20621BA795D700C8E65B /* Contact.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Contact.h; sourceTree = ""; }; 34 | 931E20631BA795D700C8E65B /* Contact.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Contact.m; sourceTree = ""; }; 35 | 931E20641BA795D700C8E65B /* ContactCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ContactCell.h; sourceTree = ""; }; 36 | 931E20651BA795D700C8E65B /* ContactCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ContactCell.m; sourceTree = ""; }; 37 | 931E20661BA795D700C8E65B /* ContactCell.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ContactCell.xib; sourceTree = ""; }; 38 | 931E20671BA795D700C8E65B /* WCSContactPicker.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WCSContactPicker.h; sourceTree = ""; }; 39 | 931E20681BA795D700C8E65B /* WCSContactPicker.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = WCSContactPicker.m; sourceTree = ""; }; 40 | /* End PBXFileReference section */ 41 | 42 | /* Begin PBXFrameworksBuildPhase section */ 43 | 931E20441BA795CE00C8E65B /* Frameworks */ = { 44 | isa = PBXFrameworksBuildPhase; 45 | buildActionMask = 2147483647; 46 | files = ( 47 | ); 48 | runOnlyForDeploymentPostprocessing = 0; 49 | }; 50 | /* End PBXFrameworksBuildPhase section */ 51 | 52 | /* Begin PBXGroup section */ 53 | 931E203E1BA795CE00C8E65B = { 54 | isa = PBXGroup; 55 | children = ( 56 | 931E205B1BA795CE00C8E65B /* Info.plist */, 57 | 931E204D1BA795CE00C8E65B /* AppDelegate.h */, 58 | 931E204E1BA795CE00C8E65B /* AppDelegate.m */, 59 | 931E20531BA795CE00C8E65B /* Main.storyboard */, 60 | 931E20581BA795CE00C8E65B /* LaunchScreen.storyboard */, 61 | 931E20561BA795CE00C8E65B /* Assets.xcassets */, 62 | 931E20611BA795D700C8E65B /* WCSContactPicker */, 63 | 931E20491BA795CE00C8E65B /* WCSContacts */, 64 | 931E20481BA795CE00C8E65B /* Products */, 65 | ); 66 | sourceTree = ""; 67 | }; 68 | 931E20481BA795CE00C8E65B /* Products */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 931E20471BA795CE00C8E65B /* WCSContacts.app */, 72 | ); 73 | name = Products; 74 | sourceTree = ""; 75 | }; 76 | 931E20491BA795CE00C8E65B /* WCSContacts */ = { 77 | isa = PBXGroup; 78 | children = ( 79 | 931E20501BA795CE00C8E65B /* ViewController.h */, 80 | 931E20511BA795CE00C8E65B /* ViewController.m */, 81 | 931E204A1BA795CE00C8E65B /* Supporting Files */, 82 | ); 83 | path = WCSContacts; 84 | sourceTree = ""; 85 | }; 86 | 931E204A1BA795CE00C8E65B /* Supporting Files */ = { 87 | isa = PBXGroup; 88 | children = ( 89 | 931E204B1BA795CE00C8E65B /* main.m */, 90 | ); 91 | name = "Supporting Files"; 92 | sourceTree = ""; 93 | }; 94 | 931E20611BA795D700C8E65B /* WCSContactPicker */ = { 95 | isa = PBXGroup; 96 | children = ( 97 | 931E20621BA795D700C8E65B /* Contact.h */, 98 | 931E20631BA795D700C8E65B /* Contact.m */, 99 | 931E20641BA795D700C8E65B /* ContactCell.h */, 100 | 931E20651BA795D700C8E65B /* ContactCell.m */, 101 | 931E20661BA795D700C8E65B /* ContactCell.xib */, 102 | 931E20671BA795D700C8E65B /* WCSContactPicker.h */, 103 | 931E20681BA795D700C8E65B /* WCSContactPicker.m */, 104 | ); 105 | path = WCSContactPicker; 106 | sourceTree = ""; 107 | }; 108 | /* End PBXGroup section */ 109 | 110 | /* Begin PBXNativeTarget section */ 111 | 931E20461BA795CE00C8E65B /* WCSContacts */ = { 112 | isa = PBXNativeTarget; 113 | buildConfigurationList = 931E205E1BA795CE00C8E65B /* Build configuration list for PBXNativeTarget "WCSContacts" */; 114 | buildPhases = ( 115 | 931E20431BA795CE00C8E65B /* Sources */, 116 | 931E20441BA795CE00C8E65B /* Frameworks */, 117 | 931E20451BA795CE00C8E65B /* Resources */, 118 | ); 119 | buildRules = ( 120 | ); 121 | dependencies = ( 122 | ); 123 | name = WCSContacts; 124 | productName = WCSContacts; 125 | productReference = 931E20471BA795CE00C8E65B /* WCSContacts.app */; 126 | productType = "com.apple.product-type.application"; 127 | }; 128 | /* End PBXNativeTarget section */ 129 | 130 | /* Begin PBXProject section */ 131 | 931E203F1BA795CE00C8E65B /* Project object */ = { 132 | isa = PBXProject; 133 | attributes = { 134 | LastUpgradeCheck = 0700; 135 | ORGANIZATIONNAME = "Wrights Creative Services, L.L.C."; 136 | TargetAttributes = { 137 | 931E20461BA795CE00C8E65B = { 138 | CreatedOnToolsVersion = 7.0; 139 | }; 140 | }; 141 | }; 142 | buildConfigurationList = 931E20421BA795CE00C8E65B /* Build configuration list for PBXProject "WCSContacts" */; 143 | compatibilityVersion = "Xcode 3.2"; 144 | developmentRegion = English; 145 | hasScannedForEncodings = 0; 146 | knownRegions = ( 147 | en, 148 | Base, 149 | ); 150 | mainGroup = 931E203E1BA795CE00C8E65B; 151 | productRefGroup = 931E20481BA795CE00C8E65B /* Products */; 152 | projectDirPath = ""; 153 | projectRoot = ""; 154 | targets = ( 155 | 931E20461BA795CE00C8E65B /* WCSContacts */, 156 | ); 157 | }; 158 | /* End PBXProject section */ 159 | 160 | /* Begin PBXResourcesBuildPhase section */ 161 | 931E20451BA795CE00C8E65B /* Resources */ = { 162 | isa = PBXResourcesBuildPhase; 163 | buildActionMask = 2147483647; 164 | files = ( 165 | 931E206B1BA795D700C8E65B /* ContactCell.xib in Resources */, 166 | 931E205A1BA795CE00C8E65B /* LaunchScreen.storyboard in Resources */, 167 | 931E20571BA795CE00C8E65B /* Assets.xcassets in Resources */, 168 | 931E20551BA795CE00C8E65B /* Main.storyboard in Resources */, 169 | ); 170 | runOnlyForDeploymentPostprocessing = 0; 171 | }; 172 | /* End PBXResourcesBuildPhase section */ 173 | 174 | /* Begin PBXSourcesBuildPhase section */ 175 | 931E20431BA795CE00C8E65B /* Sources */ = { 176 | isa = PBXSourcesBuildPhase; 177 | buildActionMask = 2147483647; 178 | files = ( 179 | 931E206A1BA795D700C8E65B /* ContactCell.m in Sources */, 180 | 931E20691BA795D700C8E65B /* Contact.m in Sources */, 181 | 931E20521BA795CE00C8E65B /* ViewController.m in Sources */, 182 | 931E204F1BA795CE00C8E65B /* AppDelegate.m in Sources */, 183 | 931E206C1BA795D700C8E65B /* WCSContactPicker.m in Sources */, 184 | 931E204C1BA795CE00C8E65B /* main.m in Sources */, 185 | ); 186 | runOnlyForDeploymentPostprocessing = 0; 187 | }; 188 | /* End PBXSourcesBuildPhase section */ 189 | 190 | /* Begin PBXVariantGroup section */ 191 | 931E20531BA795CE00C8E65B /* Main.storyboard */ = { 192 | isa = PBXVariantGroup; 193 | children = ( 194 | 931E20541BA795CE00C8E65B /* Base */, 195 | ); 196 | name = Main.storyboard; 197 | path = WCSContacts; 198 | sourceTree = ""; 199 | }; 200 | 931E20581BA795CE00C8E65B /* LaunchScreen.storyboard */ = { 201 | isa = PBXVariantGroup; 202 | children = ( 203 | 931E20591BA795CE00C8E65B /* Base */, 204 | ); 205 | name = LaunchScreen.storyboard; 206 | path = WCSContacts; 207 | sourceTree = ""; 208 | }; 209 | /* End PBXVariantGroup section */ 210 | 211 | /* Begin XCBuildConfiguration section */ 212 | 931E205C1BA795CE00C8E65B /* Debug */ = { 213 | isa = XCBuildConfiguration; 214 | buildSettings = { 215 | ALWAYS_SEARCH_USER_PATHS = NO; 216 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 217 | CLANG_CXX_LIBRARY = "libc++"; 218 | CLANG_ENABLE_MODULES = YES; 219 | CLANG_ENABLE_OBJC_ARC = YES; 220 | CLANG_WARN_BOOL_CONVERSION = YES; 221 | CLANG_WARN_CONSTANT_CONVERSION = YES; 222 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 223 | CLANG_WARN_EMPTY_BODY = YES; 224 | CLANG_WARN_ENUM_CONVERSION = YES; 225 | CLANG_WARN_INT_CONVERSION = YES; 226 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 227 | CLANG_WARN_UNREACHABLE_CODE = YES; 228 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 229 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 230 | COPY_PHASE_STRIP = NO; 231 | DEBUG_INFORMATION_FORMAT = dwarf; 232 | ENABLE_STRICT_OBJC_MSGSEND = YES; 233 | ENABLE_TESTABILITY = YES; 234 | GCC_C_LANGUAGE_STANDARD = gnu99; 235 | GCC_DYNAMIC_NO_PIC = NO; 236 | GCC_NO_COMMON_BLOCKS = YES; 237 | GCC_OPTIMIZATION_LEVEL = 0; 238 | GCC_PREPROCESSOR_DEFINITIONS = ( 239 | "DEBUG=1", 240 | "$(inherited)", 241 | ); 242 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 243 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 244 | GCC_WARN_UNDECLARED_SELECTOR = YES; 245 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 246 | GCC_WARN_UNUSED_FUNCTION = YES; 247 | GCC_WARN_UNUSED_VARIABLE = YES; 248 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 249 | MTL_ENABLE_DEBUG_INFO = YES; 250 | ONLY_ACTIVE_ARCH = YES; 251 | SDKROOT = iphoneos; 252 | }; 253 | name = Debug; 254 | }; 255 | 931E205D1BA795CE00C8E65B /* Release */ = { 256 | isa = XCBuildConfiguration; 257 | buildSettings = { 258 | ALWAYS_SEARCH_USER_PATHS = NO; 259 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 260 | CLANG_CXX_LIBRARY = "libc++"; 261 | CLANG_ENABLE_MODULES = YES; 262 | CLANG_ENABLE_OBJC_ARC = YES; 263 | CLANG_WARN_BOOL_CONVERSION = YES; 264 | CLANG_WARN_CONSTANT_CONVERSION = YES; 265 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 266 | CLANG_WARN_EMPTY_BODY = YES; 267 | CLANG_WARN_ENUM_CONVERSION = YES; 268 | CLANG_WARN_INT_CONVERSION = YES; 269 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 270 | CLANG_WARN_UNREACHABLE_CODE = YES; 271 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 272 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 273 | COPY_PHASE_STRIP = NO; 274 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 275 | ENABLE_NS_ASSERTIONS = NO; 276 | ENABLE_STRICT_OBJC_MSGSEND = YES; 277 | GCC_C_LANGUAGE_STANDARD = gnu99; 278 | GCC_NO_COMMON_BLOCKS = YES; 279 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 280 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 281 | GCC_WARN_UNDECLARED_SELECTOR = YES; 282 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 283 | GCC_WARN_UNUSED_FUNCTION = YES; 284 | GCC_WARN_UNUSED_VARIABLE = YES; 285 | IPHONEOS_DEPLOYMENT_TARGET = 9.0; 286 | MTL_ENABLE_DEBUG_INFO = NO; 287 | SDKROOT = iphoneos; 288 | VALIDATE_PRODUCT = YES; 289 | }; 290 | name = Release; 291 | }; 292 | 931E205F1BA795CE00C8E65B /* Debug */ = { 293 | isa = XCBuildConfiguration; 294 | buildSettings = { 295 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 296 | INFOPLIST_FILE = WCSContacts/Info.plist; 297 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 298 | PRODUCT_BUNDLE_IDENTIFIER = com.wrightscs.wcscontacts; 299 | PRODUCT_NAME = "$(TARGET_NAME)"; 300 | }; 301 | name = Debug; 302 | }; 303 | 931E20601BA795CE00C8E65B /* Release */ = { 304 | isa = XCBuildConfiguration; 305 | buildSettings = { 306 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 307 | INFOPLIST_FILE = WCSContacts/Info.plist; 308 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 309 | PRODUCT_BUNDLE_IDENTIFIER = com.wrightscs.wcscontacts; 310 | PRODUCT_NAME = "$(TARGET_NAME)"; 311 | }; 312 | name = Release; 313 | }; 314 | /* End XCBuildConfiguration section */ 315 | 316 | /* Begin XCConfigurationList section */ 317 | 931E20421BA795CE00C8E65B /* Build configuration list for PBXProject "WCSContacts" */ = { 318 | isa = XCConfigurationList; 319 | buildConfigurations = ( 320 | 931E205C1BA795CE00C8E65B /* Debug */, 321 | 931E205D1BA795CE00C8E65B /* Release */, 322 | ); 323 | defaultConfigurationIsVisible = 0; 324 | defaultConfigurationName = Release; 325 | }; 326 | 931E205E1BA795CE00C8E65B /* Build configuration list for PBXNativeTarget "WCSContacts" */ = { 327 | isa = XCConfigurationList; 328 | buildConfigurations = ( 329 | 931E205F1BA795CE00C8E65B /* Debug */, 330 | 931E20601BA795CE00C8E65B /* Release */, 331 | ); 332 | defaultConfigurationIsVisible = 0; 333 | }; 334 | /* End XCConfigurationList section */ 335 | }; 336 | rootObject = 931E203F1BA795CE00C8E65B /* Project object */; 337 | } 338 | -------------------------------------------------------------------------------- /WCSContacts.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /WCSContacts.xcodeproj/xcuserdata/Aaron.xcuserdatad/xcschemes/WCSContacts.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 39 | 40 | 41 | 42 | 43 | 44 | 54 | 56 | 62 | 63 | 64 | 65 | 66 | 67 | 73 | 75 | 81 | 82 | 83 | 84 | 86 | 87 | 90 | 91 | 92 | -------------------------------------------------------------------------------- /WCSContacts.xcodeproj/xcuserdata/Aaron.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | WCSContacts.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 931E20461BA795CE00C8E65B 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /WCSContacts/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // WCSContacts 4 | // 5 | // Created by Aaron on 9/14/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /WCSContacts/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // WCSContacts 4 | // 5 | // Created by Aaron on 9/14/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /WCSContacts/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /WCSContacts/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /WCSContacts/Assets.xcassets/contact-image-none.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "contact-image-none.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "filename" : "contact-image-none-1.png", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "universal", 15 | "scale" : "3x" 16 | } 17 | ], 18 | "info" : { 19 | "version" : 1, 20 | "author" : "xcode" 21 | } 22 | } -------------------------------------------------------------------------------- /WCSContacts/Assets.xcassets/contact-image-none.imageset/contact-image-none-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/299619934025a73d1a780011bf5397ba80831b98/WCSContacts/Assets.xcassets/contact-image-none.imageset/contact-image-none-1.png -------------------------------------------------------------------------------- /WCSContacts/Assets.xcassets/contact-image-none.imageset/contact-image-none.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/299619934025a73d1a780011bf5397ba80831b98/WCSContacts/Assets.xcassets/contact-image-none.imageset/contact-image-none.png -------------------------------------------------------------------------------- /WCSContacts/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /WCSContacts/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 26 | 33 | 41 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /WCSContacts/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /WCSContacts/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // WCSContacts 4 | // 5 | // Created by Aaron C. Wright on 9/14/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import 13 | 14 | @interface ViewController : UIViewController 15 | 16 | 17 | @end 18 | 19 | -------------------------------------------------------------------------------- /WCSContacts/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // WCSContacts 4 | // 5 | // Created by Aaron C. Wright on 9/14/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import "WCSContactPicker.h" 13 | #import "ViewController.h" 14 | 15 | @interface ViewController () 16 | @property (nonatomic, weak) IBOutlet UIImageView * imageThumb; 17 | @property (nonatomic, weak) IBOutlet UILabel * labelName, * labelPhone, * labelEmail; 18 | @end 19 | 20 | @implementation ViewController 21 | 22 | - (void)viewDidLoad { 23 | [super viewDidLoad]; 24 | // Do any additional setup after loading the view, typically from a nib. 25 | } 26 | 27 | - (void)didReceiveMemoryWarning { 28 | [super didReceiveMemoryWarning]; 29 | // Dispose of any resources that can be recreated. 30 | } 31 | 32 | #pragma mark - Private Methods 33 | 34 | 35 | 36 | #pragma mark IBActions 37 | 38 | - (IBAction)selectContact:(id)sender { 39 | WCSContactPicker * _picker = [[WCSContactPicker alloc] initWithDelegate:self]; 40 | UINavigationController * controller = [[UINavigationController alloc] initWithRootViewController:_picker]; 41 | [self presentViewController:controller animated:YES completion:NULL]; 42 | } 43 | 44 | #pragma mark - WCSContactPicker Delegates 45 | 46 | - (void)didCancelContactSelection { 47 | NSLog(@"Canceled Contact Selection."); 48 | } 49 | - (void)picker:(WCSContactPicker *)picker didFailToAccessContacts:(NSError *)error { 50 | NSLog(@"Failed to Access Contacts: %@", error.description); 51 | } 52 | - (void)picker:(WCSContactPicker *)picker didSelectContact:(Contact *)contact { 53 | NSLog(@"Selected Contact: %@", contact.description); 54 | _imageThumb.image = contact.photo; 55 | _labelName.text = contact.displayName; 56 | _labelPhone.text = contact.phones[0]; 57 | _labelEmail.text = contact.emails[0]; 58 | } 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /WCSContacts/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // WCSContacts 4 | // 5 | // Created by Aaron C. Wright on 9/14/15. 6 | // Copyright © 2015 Wrights Creative Services, L.L.C. All rights reserved. 7 | // 8 | // aaron@wrightscs.com 9 | // http://www.wrightscs.com, http://www.wrightscsapps.com 10 | // 11 | 12 | #import 13 | #import "AppDelegate.h" 14 | 15 | int main(int argc, char * argv[]) { 16 | @autoreleasepool { 17 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /screens/screen-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/299619934025a73d1a780011bf5397ba80831b98/screens/screen-1.png -------------------------------------------------------------------------------- /screens/screen-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/299619934025a73d1a780011bf5397ba80831b98/screens/screen-2.png -------------------------------------------------------------------------------- /screens/screen-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/WrightsCS/WCSContactPicker/299619934025a73d1a780011bf5397ba80831b98/screens/screen-3.png --------------------------------------------------------------------------------