Search code examples
iosswiftuipickerviewuialertcontroller

UIPickerView within UIAlertController action sheet is not displaying any data


I'm trying to create a UIPickerView programmatically and display it's rows within an action sheet. However, nothing seems to be working. Here is a simplified example of similar non-working code:

import UIKit

class ViewController: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {

    let array = ["one","two","three","four","five"]
    var controller: UIAlertController?
    var pickerView = UIPickerView(frame: CGRectMake(0, 15, 304, 0))

    @IBOutlet weak var button: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        controller = UIAlertController(title: "Choose Category", message: "\n\n\n\n\n\n\n\n", preferredStyle: .ActionSheet)
        let doneAction = UIAlertAction(title: "Done", style: .Default, handler: nil)
        controller!.addAction(doneAction)

        pickerView.delegate = self
        pickerView.dataSource = self
    }

   @IBAction func buttonPressed(sender: AnyObject) {
        controller!.view.addSubview(self.pickerView)
        self.presentViewController(controller!, animated: true, completion: nil)
    }

    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }

    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return array.count
    }

    func pickerView(pickerView: UIPickerView, rowHeightForComponent component: Int) -> CGFloat {
        return 50.0
    }

    func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView?) -> UIView {
        let view = UIView(frame: CGRectMake(0, 0, 100, 70))

        let label = UILabel(frame: CGRectMake(50, 5, 100, 60))
        label.text = array[row] as String

        view.insertSubview(label, atIndex: 1)

        return view
    }
}

When the button is pressed, this is the output:

Screenshot of a UIAlertController being displayed on an iPhone 4S

As you can see, the action sheet is not being populated with the array values. This was all working properly before the I upgraded to iOS 9 and Swift 2.0. I've used print to make sure the pickerView methods are being called which they are and even using print to check the value of label and view and they are there. Can anyone either guide me in a direction or explain what is causing this to not be displayed?

Also: Another funky thing is how these methods are being called. If I press the button once, this is the order of every method call that happens:

numberOfComponentsInPickerView:
numberOfComponentsInPickerView:
rowHeightForComponent:
rowHeightForComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfComponentsInPickerView:
numberOfRowsInComponent:
viewForRow:
viewForRow:
numberOfComponentsInPickerView:
rowHeightForComponent:
rowHeightForComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
numberOfRowsInComponent:
viewForRow:
viewForRow:
viewForRow:
viewForRow:
viewForRow:

Solution

  • You're not supposed to modify the view hierarchy of a UIAlertController. Even if you could get it to work that way, you risk Apple breaking it anytime there's an update and you'd have to keep finding new workarounds to make it work. You may want to consider putting your picker in a view controller and presenting it as a UIModalPresentationPopover. If you're using it with a responder subclass like a text field or a custom one you make, you can also make a view that looks like the action sheet with a picker and set it as the inputView of the responder.