Reputation: 6714
I have a button to import contacts from the user's address book. When they tap the button for the first time, my code returns a bool indicating whether user has granted permission or not. If permission is granted, then the contacts are imported and I perform a segue to a table view. If permission is not granted then the contacts are not imported and I perform the same segue to an empty table view. Here's what I have:
func myImportThenSegueFunction() {
if userHasAuthorizedAddressBookAccess() == true {
// Import contacts and perform segue
} else {
// Just perform segue
}
}
func userHasAuthorizedAddressBookAccess() -> Bool {
switch ABAddressBookGetAuthorizationStatus() {
case .Authorized:
return true
case .NotDetermined:
var userDidAuthorize: Bool!
ABAddressBookRequestAccessWithCompletion(nil) { (granted: Bool, error: CFError!) in
if granted {
userDidAuthorize = true
} else {
userDidAuthorize = false
}
}
return userDidAuthorize
case .Restricted:
return false
case .Denied:
return false
}
}
The problem is that when the button is tapped, the permission to access settings alert is briefly displayed while in the background the view performs the segue before the user has either granted or denied access in the alert prompt. Then the app immediately crashes saying that .NotDetermined
returned nil
meaning the variable userDidAuthorize
returned before the user could even make a selection to set userDidAuthorize
in the if/else block in ABAddressBookRequestAccessWithCompletion(nil)
.
My question is why does the code execute return
in the case .NotDetermined
before the user sets the variable userDidAuthorize
to return the proper bool via the alert prompt? I've seen some hacks to wrap the execution in a time delay and I know this functionality is deprecated. How would I get this to work properly?
Upvotes: 0
Views: 401
Reputation: 119041
Because ABAddressBookRequestAccessWithCompletion
is asynchronous and returns immediately. It needs to be like this as it's usually used from the main thread and can't block while the user is asked for permission.
You need to change the way you use it to embrace this, by calling a completion block with the status once you know it rather than returning the status immediately.
Upvotes: 0