I am creating UIPickerView
programatically and then adding it to UIAlertController
. I've also created a class called StringPickerDelegate
, which implements the picker's delegate and data source protocols.
Here's my code when creating the UIPickerView
let pickerView = UIPickerView(frame: CGRect(x: 5, y: 20, width: 250, height: 140))
alertController.view.addSubview(pickerView)
let delegate = StringPickerDelegate(items: items) { index, item in
onItemSelected?(item)
}
pickerView.dataSource = delegate
pickerView.delegate = delegate
And here's the StringPickerDelegate
class
class StringPickerDelegate: NSObject, UIPickerViewDelegate, UIPickerViewDataSource {
private let items: [String]
private let didSelectItem: ((Int, String) -> Void)
init(items: [String], didSelectItem: @escaping ((Int, String) -> Void)) {
self.items = items
self.didSelectItem = didSelectItem
}
// MARK: UIPickerViewDataSource
func numberOfComponents(in pickerView: UIPickerView) -> Int {
return 1
}
func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
return items.count
}
func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
return items[row]
}
// MARK: UIPickerViewDelegate
func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
didSelectItem(row, items[row])
}
}
I really can't comprehend why the methods are not getting called. The class properly implements both delegates and I'm also making sure that UIPickerView
is getting allocated and added as a subview before settings the delegate and data source.
Edit: I've also tried settings delegates AFTER the UIAlertController
is presented to make sure all of the views are fully instantiated, but the result is the same.
UIPickerView.delegate
is declared as weak
(as is most other delegates):
weak var delegate: UIPickerViewDelegate? { get set }
This means that the picker only holds a weak reference it. After your code executes, nothing else would hold a strong reference to the StringPickerDelegate
, so it will be deinitialised!
You need to store an instance of StringPickerDelegate
in your VC:
// outside of any method
var pickerDelegate: StringPickerDelegate?
// ...
pickerDelegate = StringPickerDelegate(items: items) { index, item in
onItemSelected?(item)
}
pickerView.dataSource = pickerDelegate!
pickerView.delegate = pickerDelegate!