UIPickerView 委托在以编程方式创建时从不调用

Posted

技术标签:

【中文标题】UIPickerView 委托在以编程方式创建时从不调用【英文标题】:UIPickerView delegate never called when created programatically 【发布时间】:2020-09-02 12:30:00 【问题描述】:

我正在以编程方式创建UIPickerView,然后将其添加到UIAlertController。我还创建了一个名为StringPickerDelegate 的类,它实现了选择器的委托和数据源协议。

这是我创建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

这是StringPickerDelegate

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])
    


我真的无法理解为什么没有调用这些方法。该类正确实现了两个委托,我还确保UIPickerView 被分配并添加为子视图设置委托和数据源之前。

编辑:我还尝试在 UIAlertController 出现后设置委托,以确保所有视图都已完全实例化,但结果是相同的。

【问题讨论】:

【参考方案1】:

UIPickerView.delegate 被声明为 weak(与大多数其他代表一样):

weak var delegate: UIPickerViewDelegate?  get set 

这意味着选择器只持有一个弱引用它。在您的代码执行后,没有其他东西可以对StringPickerDelegate 进行强引用,因此它将被取消初始化!

您需要在 VC 中存储StringPickerDelegate 的实例:

// outside of any method
var pickerDelegate: StringPickerDelegate?

// ...
pickerDelegate = StringPickerDelegate(items: items)  index, item in
    onItemSelected?(item)

pickerView.dataSource = pickerDelegate!
pickerView.delegate = pickerDelegate!

【讨论】:

非常感谢,这很有意义。刚刚试了一下,效果很好。

以上是关于UIPickerView 委托在以编程方式创建时从不调用的主要内容,如果未能解决你的问题,请参考以下文章

为 UIPickerView 创建委托和数据源

以编程方式创建和显示 UIPickerView

iOS:以编程方式在以编程方式创建的滚动视图中创建标签

在以编程方式创建的 UICollectionView 中未调用 didDeselectItemAtIndexPath 函数

即使在 [[UIPickerView alloc] init] 之后设置了委托,也没有调用 UIPickerView 委托方法

故事板集合视图拒绝在以编程方式创建的按钮前面