Aaron
Aaron

Reputation: 6714

Permission alert to access user's address book does not halt execution

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

Answers (1)

Wain
Wain

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

Related Questions