this code has been posted before, and been used as well, from what i could gather. i'm in a situation where i need the code to NOT continue until i know if i have access to the contacts.
on Xcode 5.0.2 and iOS 6, this works just fine. on iOS 7, it hangs forever, and then when i kill the app the dialog box comes up asking to allow access to the contacts.
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);
}
else { // we're on iOS 5 or older
accessGranted = YES;
}
in trying to play with this, i then simply set a BOOL to be NO, and then set it to YES within the block. after the block, i put a while loop that checked for the variable being YES, then slept for 1 second. works perfectly fine on 6, on 7 i never reach the NSLog statement in the block, and i'm stuck forever in the while loop printing the log statement.
am i doing something really lame here? or is this method gone haywire on 7?
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (granted)
{
self.myAddressBook = addressBook;
}
done = YES;
NSLog(#"in block, done is %#", done ? #"YES" : #"NO");
didGrant = granted;
//dispatch_semaphore_signal(sema);
});
while (!done)
{
NSLog(#"done is %#", done ? #"YES" : #"NO");
sleep(1);
}
I had the same problem, and I realised that the Dialog box that requests access to the contacts blocks the app anyways, so maybe there's a deadlock. So I just ditched the semaphores and did something like this (tested and works on iOS 7.1.1):
ABAddressBookRef addressBook = ABAddressBookCreate();
MyController * __weak weakSelf = self;
if (ABAddressBookRequestAccessWithCompletion != NULL)
{ // we're on iOS 6
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined)
{
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
dispatch_async(dispatch_get_main_queue(), ^{
[weakSelf accessGrantedForAddressBook];
});
});
}
else
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusAuthorized); //Maybe add something here to handle kABAuthorizationStatusRestricted
[self accessGrantedForAddressBook];
}
}
else // we're on iOS 5 or older
[self accessGrantedForAddressBook];
which is quite similar to what Apple does in their documentation (search for ABAddressBookRequestAccessWithCompletion). Besides, what's the point of ABAddressBookRequestAccessWithCompletion being asynchronous and waiting for it (see here)..
Related
I want to retrieve contacts from AddressBook into my App. The code is having problem for first install, next time onwards it is working fine. For the first installation of App, if AddressBook code executes, the App hangs. After execution of dispatch_semaphore_wait line, the App hangs. I restarted the device, this time App works fine. It is happening if it is first install on new device. How can i fix this?
CFErrorRef * error = NULL;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, NULL);
__block BOOL isaccess = NO;
if(ABAddressBookRequestAccessWithCompletion != NULL) {
dispatch_semaphore_t sema = dispatch_semaphore_create(0);
//ask to grand or deny access
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
isaccess = granted;
dispatch_semaphore_signal(sema);
});
dispatch_semaphore_wait(sema, DISPATCH_TIME_FOREVER);
dispatch_release(sema);
}
On a Stackoverflow question (see "Source 1" at the bottom), I see the following pattern when working with AddressBook in which the programmer wants to block the main thread until the user has granted (or denied) access to his/her AddressBook:
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...
}
but according to the documentation (ABAddressBook Reference), the completion handler is executed on an arbitrary queue, which means it could be executed on the main queue. If the completion handler were placed on the main queue, then the above code would result in a deadlock. Is there any documentation guaranteeing that the completion handler will not be placed on the main queue?
ABAddressBook Reference: "The completion handler is called on an arbitrary queue. If your app uses an address book throughout the app, you are responsible for ensuring that all usage of that address book is dispatched to a single queue to ensure correct thread-safe operation."
Source:
First answer to: How do I correctly use ABAddressBookCreateWithOptions method in iOS 6?
In one of my apps I am using dispatch_queue and inside this I declared a dispatch_asyc queue for checking the address book. Now when compiler comes to the return statement, it causes app to crash. Below is my source code.
dispatch_queue_t queue = dispatch_queue_create("abc", NULL);
dispatch_async(queue, ^{
// Request authorization to Address Book
ABAddressBookRef addressBookRef = ABAddressBookCreateWithOptions(NULL, NULL);
if (ABAddressBookGetAuthorizationStatus() == kABAuthorizationStatusNotDetermined) {
ABAddressBookRequestAccessWithCompletion(addressBookRef, ^(bool granted, CFErrorRef error) {
// First time access has been granted...
// All good.
completionBlock?completionBlock(YES):nil;
dispatch_async(queue, ^{
if (addressBookRef) {
CFRelease(addressBookRef);
};
});
return;
});
According to the documentation on Address Book, you cannot use ABAddressBookRef across threads
Important: Instances of ABAddressBookRef cannot be used by
multiple threads. Each thread must make its own instance by calling
ABAddressBookCreate.
See this question for some more ideas on how to do this:
I have the following code:
NSMutableArray *contacts = [[NSMutableArray alloc]init];
CFErrorRef *error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, error);
if (error)
}
NSArray *arrayOfPeople = (__bridge_transfer NSArray*)ABAddressBookCopyArrayOfAllPeople(addressBook);
It works on the simulator and gives me the expected results - however on the device the number of contacts is 0 and there is no error (the app strangely does not ask me for permissions to access the address book - I even deleted and reinstalled the app)
Any Ideas ?
Thanks in advance
On ios 6 you need get access to the Address Book.
Call ABAddressBookRequestAccessWithCompletion() to get the permission.
see this and AddressHelper
CFErrorRef error = nil;
ABAddressBookRef addressBook = ABAddressBookCreateWithOptions(NULL, &error);
ABAddressBookRequestAccessWithCompletion(addressBook, ^(bool granted, CFErrorRef error) {
if (error) {
NSLog(#"error %#", error);
}else if (granted){
// Do what you want with the Address Book
}else{
NSLog(#"permission denied");
}
CFRelease(addressBook);
});
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Programmatically Request Access to Contacts in iOS 6
I'm trying to test out some functionality on my iPhone in which I pull all the address book members and display them in a table. This works fine on the simulator, and I see the mock contacts like "John Appleseed". When I run the code on my iPhone, I only see "Mobile User" which apparently is me.
How do I see all my address book contacts?
In iOS 6 the user has to give permission to apps to use the contact information.
There are a lot examples of this if you google for it. You could use something like:
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) {
// Do whatever you want here.
}
Check out this question for more information:
Programmatically Request Access to Contacts