Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I correctly use ABAddressBookCreateWithOptions method in iOS 6?

I am trying to understand the ABAdressBookCreateWithOptions and ABAddressBookRequestAccessWithCompletion methods in iOS 6.

The most information i have been able to find is the following, "To request access to contact data, call the ABAddressBookRequestAccessWithCompletion function after calling the ABAddressBookCreateWithOptions function."

I believe together these methods should alert the user to decide whether to allow the application access to contacts, however when I use them I am seeing no prompt.

Could someone provide some sample code of how these methods should be called together in a real world example? How do I create (CFDictionary) options? I have working code using the deprecated ABAddressBookCreate method, but need to update to iOS 6 to accommodate privacy concerns.

Thanks in advance to anyone who can shed some light here!

like image 601
codeqi Avatar asked Aug 23 '12 01:08

codeqi


2 Answers

Now that the NDA has been lifted, here is my solution for this for the where you need replace a method which returns an Array. (If you'd rather not block while the user is deciding and are ready to potentially rewrite some of your existing code, please look at David's solution below):

ABAddressBookRef addressBook = ABAddressBookCreate();  __block BOOL accessGranted = NO;  if (ABAddressBookRequestAccessWithCompletion != NULL) { // we're on iOS 6     dispatch_semaphore_t sema = dispatch_semaphore_create(0);      ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {         accessGranted = granted;         dispatch_semaphore_signal(sema);     });      dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);     dispatch_release(sema);     } else { // we're on iOS 5 or older     accessGranted = YES; }   if (accessGranted) {      NSArray *thePeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);     // Do whatever you need with thePeople...  } 

Hope this helps somebody...

like image 195
Engin Kurutepe Avatar answered Oct 04 '22 05:10

Engin Kurutepe


Most answers I've seen to this question do crazy complicated things with GCD and end up blocking the main thread. It's not necessary!

Here's the solution I've been using (works on iOS 5 and iOS 6):

- (void)fetchContacts:(void (^)(NSArray *contacts))success failure:(void (^)(NSError *error))failure {   if (ABAddressBookRequestAccessWithCompletion) {     // on iOS 6      CFErrorRef err;     ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &err);      if (err) {       // handle error       CFRelease(err);       return;     }      ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {       // ABAddressBook doesn't gaurantee execution of this block on main thread, but we want our callbacks to be       dispatch_async(dispatch_get_main_queue(), ^{         if (!granted) {           failure((__bridge NSError *)error);         } else {           readAddressBookContacts(addressBook, success);         }         CFRelease(addressBook);       });     });   } else {     // on iOS < 6      ABAddressBookRef addressBook = ABAddressBookCreate();     readAddressBookContacts(addressBook, success);     CFRelease(addressBook);   } }  static void readAddressBookContacts(ABAddressBookRef addressBook, void (^completion)(NSArray *contacts)) {   // do stuff with addressBook   NSArray *contacts = @[];    completion(contacts); } 
like image 36
Nik Avatar answered Oct 04 '22 07:10

Nik