Presenting UIAlertController ActionSheet in popover on iPhone

Ashley Mills picture Ashley Mills · Sep 16, 2014 · Viewed 7.1k times · Source

I'm creating and presenting an ActionSheet as follows:

let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
alertController.modalPresentationStyle = .Popover

// Add some buttons

alertController.popoverPresentationController?.delegate = self
alertController.popoverPresentationController?.barButtonItem = someBarButton

self.presentViewController(alertController, animated: true, completion: nil)

This works fine on the iPad, but alertController.popoverPresentationController is nil on the iPhone.

I've successfully presented popovers on the iPhone using adaptive segue style Present As Popover in interface builder and implementing adaptivePresentationStyleForPresentationController delegate method to return the correct UIModalPresentationStyle but I'm stuck how to do it in code with UIAlertController as it has no popoverPresentationController on the iPhone

Answer

Korey Hinton picture Korey Hinton · Mar 15, 2016

UIAlertController is not meant to be a popover. There seems to be some controversy about this in the comments. Your code above wouldn't work if it was actually respecting the .Popover style. Why? Because it needs to have a sourceView and a sourceRect set on the popoverPresentationController object to know where to point the arrow. If you swap UIAlertController out for UIViewController it'll crash because those values aren't set. Ironically if you do try force unwrap the popoverPresentationController it'll crash:

alertController.modalPresentationStyle = .Popover
alertController.popoverPresentationController!.sourceView = sender // CRASH!!!
alertController.popoverPresentationController!.sourceRect = sender.bounds

For all details on how to implement an iPhone popover (for everything else but UIAlertController) look at my iPhone Popover blog post.

The fact that the popover presentation controller is nil is pretty telling that its not supposed to be a popover.

Table View Alternative

You might consider UITableViewController as a replacement here. Using the Grouped style actually looks pretty nice in popovers.

Picker

You are going to run into this problem probably over and over again, where you want the user to just select from a few options. I'd suggest you encapsulate whatever user interface control you're going to use into your own picker object. The implementation details of whether its a table view or just a line-up of buttons can be disguised from the calling code and you can have a delegate or closure callbacks when selection at a particular index occurs. Here's roughly what the API might look like:

class Picker: UIViewController {
    init(items: [String])
    selectionCompletion: (index: Int, item: String)->Void
}

// Usage:
let picker = Picker(["Answer A","Answer B"])
picker.selectionCompletion = { index, item in
    // handle selection
}

This way you can reuse it anywhere you'd like and the API is very simple