以编程方式创建时从未调用过UIPickerView委托

问题描述

我正在以编程方式创建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之后,我还尝试了设置委托,以确保所有视图都被完全实例化,但是结果是相同的。

解决方法

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!