kmell96
kmell96

Reputation: 1465

Run UIAlertController Completion Handler Block Before Dismiss Animation

I'm setting up a pretty standard action sheet using UIAlertController as such:

    let alert = UIAlertController(title: "title",
                                  message: nil,
                                  preferredStyle: .actionSheet)

    alert.addAction(
        UIAlertAction(title: "button",
                      style: .default,
                      handler: { _ in
                        MediaPlayer.playSound(.click)
                        // The above line just uses AVAudioPlayer to play
                        // an MP3 file. Its implementation isn't relevant
                        // to the question and can be assumed to be correct.
    }))

When I press the button, the alert dismisses, then the completion handler runs and the sound plays. Since the alert's dismiss animation takes awhile, there's a very noticeable delay between when I press the button and when the sound plays; the alert isn't even visible anymore when the sound starts.

Is there a way to play the sound as soon as the button is pressed, and not wait until the dismiss animation completes?

Moreover, is there a reason that there's not an easy way to do this? I.e. is Apple opposed to people adding click sounds to their alert buttons?

Upvotes: 3

Views: 1412

Answers (2)

Ben Packard
Ben Packard

Reputation: 26476

Rather than rebuilding UIAlertController as Matt suggests (and updating it to match iOS every time it is tweaked), I recommend simply subclassing it instead. You can give it a block of code that you want to run as it disappears. For example:

class CustomAlertController: UIAlertController {
    var onDisappear: (() -> Void)?

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)

        onDisappear?()
    }
}

You can then set this block before you display the alert controller:

let controller = CustomAlertController(title: "Title", message: nil, preferredStyle: .actionSheet)
controller.onDisappear = {
    // play sound here
}

Upvotes: 2

matt
matt

Reputation: 535138

There's basically nothing you can do about this. The delay between the user tapping and the running of the button's action handler was evident as soon as UIAlertController replaced UIAlertView:

UIAlertController dismiss is slow

In effect, you're trying to do something Apple doesn't want you to do, namely, associate a sound with an alert controller button.

My solution to this sort of thing is simple: Don't use UIAlertController. It's easy enough to build a custom presented view controller that looks just like a UIAlertController's view, and in fact a UIAlertController is a presented view controller. So just roll your own. Now the button is yours, you can detect the tap and respond with a sound and then dismiss, no problem.

Upvotes: 3

Related Questions