AddressBook.m (4221B)
1 #import "AddressBook.h" 2 3 #include <AddressBook/AddressBook.h> 4 #import <UIKit/UIKit.h> 5 6 #include "libkern/OSAtomic.h" 7 8 @interface AddressBook () 9 10 @end 11 12 // empty implementation 13 @implementation Contact 14 @end 15 16 @implementation AddressBook 17 18 + (id)shared_address_book 19 { 20 static AddressBook *address_book = nil; 21 static dispatch_once_t onceToken; 22 dispatch_once(&onceToken, ^{ 23 address_book = [[self alloc] init]; 24 }); 25 return address_book; 26 } 27 28 - (id)init 29 { 30 self = [super init]; 31 if (self) 32 { 33 _contacts = [[NSMutableArray alloc] init]; 34 ready = 0; 35 [self get_contacts_or_fail]; 36 } 37 return self; 38 } 39 40 - (void) get_contacts_or_fail 41 { 42 ABAuthorizationStatus status = ABAddressBookGetAuthorizationStatus(); 43 44 if (status == kABAuthorizationStatusDenied || status == kABAuthorizationStatusRestricted) { 45 // if you got here, user had previously denied/revoked permission for your 46 // app to access the contacts, and all you can do is handle this gracefully, 47 // perhaps telling the user that they have to go to settings to grant access 48 // to contacts 49 50 [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; 51 return; 52 } 53 54 CFErrorRef error = NULL; 55 ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error); 56 57 if (!addressBook) { 58 NSLog(@"ABAddressBookCreateWithOptions error: %@", CFBridgingRelease(error)); 59 return; 60 } 61 62 // ABAddressBookRegisterExternalChangeCallback(<#ABAddressBookRef addressBook#>, <#ABExternalChangeCallback callback#>, <#void *context#>) 63 64 ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) { 65 if (error) { 66 NSLog(@"ABAddressBookRequestAccessWithCompletion error: %@", CFBridgingRelease(error)); 67 } 68 69 if (granted) { 70 // if they gave you permission, then just carry on 71 [self listPeopleInAddressBook:addressBook]; 72 if (_main_tvc) 73 [_main_tvc update_address_book]; 74 else 75 NSLog(@"warn: address book: address book ready before main_tvc assigned!"); 76 77 // atomically set the ready flag; this completion handler 78 // can be run on an arbitrary thread 79 OSAtomicIncrement32((volatile int32_t *)&ready); 80 [_main_tvc.tableView reloadData]; 81 } else { 82 // however, if they didn't give you permission, handle it gracefully, for example... 83 84 dispatch_async(dispatch_get_main_queue(), ^{ 85 // BTW, this is not on the main thread, so dispatch UI updates back to the main queue 86 87 [[[UIAlertView alloc] initWithTitle:nil message:@"This app requires access to your contacts to function properly. Please visit to the \"Privacy\" section in the iPhone Settings app." delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil] show]; 88 }); 89 } 90 91 CFRelease(addressBook); 92 }); 93 } 94 95 96 - (void)listPeopleInAddressBook:(ABAddressBookRef)addressBook 97 { 98 NSArray *allPeople = CFBridgingRelease(ABAddressBookCopyArrayOfAllPeople(addressBook)); 99 100 NSCharacterSet *want =[[NSCharacterSet characterSetWithCharactersInString:@"0123456789"] invertedSet]; 101 102 for (NSInteger i = 0; i < [allPeople count]; i++) { 103 ABRecordRef person = (__bridge ABRecordRef)allPeople[i]; 104 Contact *contact = [[Contact alloc] init]; 105 106 // don't enforce these existing 107 contact.first_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonFirstNameProperty)); 108 contact.last_name = CFBridgingRelease(ABRecordCopyValue(person, kABPersonLastNameProperty)); 109 contact.phone_numbers = [[NSMutableArray alloc] init]; 110 111 ABMultiValueRef phoneNumbers = ABRecordCopyValue(person, kABPersonPhoneProperty); 112 CFIndex numberOfPhoneNumbers = ABMultiValueGetCount(phoneNumbers); 113 for (CFIndex i = 0; i < numberOfPhoneNumbers; i++) { 114 NSString *pn = CFBridgingRelease(ABMultiValueCopyValueAtIndex(phoneNumbers, i)); 115 116 if (pn == nil) 117 continue; 118 119 NSString *cleaned = [[pn componentsSeparatedByCharactersInSet: want] componentsJoinedByString:@""]; 120 121 [contact.phone_numbers addObject:cleaned]; 122 } 123 CFRelease(phoneNumbers); 124 125 [_contacts addObject:contact]; 126 } 127 128 _num_contacts = [_contacts count]; 129 NSLog(@"info: address book: %lu contacts found", _num_contacts); 130 } 131 132 @end