Search code examples
iosswiftdatepickeruipickerview

UIPickerView subclass in Swift : error optional value in viewForRow


I would like to subclass UIPickerView in order to create a custom DatePicker. I tried this, but there is an error in Swift saying :

unexpectedly found nil while unwrapping an Optional value

on this line : (view.viewWithTag(1) as UILabel).text = array[row]

Here is the code :

class MyPickerView : UIPickerView, UIPickerViewDataSource, UIPickerViewDelegate{

    let array = ["one", "two", "three"]
    required init(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    override init(frame: CGRect) {
        super.init(frame:frame)
        self.delegate = self
        self.dataSource = self
    }

    //components / row
    func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {
        return 1
    }
    func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return array.count
    }

    //view for row
    func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {
        if view == nil {
            var view = UIView(frame: CGRectMake(0,0, 150,50))
            let label = UILabel(frame:CGRectMake(0,0, 80, 40))
            label.tag = 1
            view.addSubview(label)
        }
        (view.viewWithTag(1) as UILabel).text = array[row]
        return view
    }
    //did select row
    func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
        println("has selected row \(row)")
    }

Thanks


Solution

  • There is a known bug in UIPickerView (started in iOS 7 I think), that the views are never reused. To fix your problem, get rid of the if clause (then there's no need for the tag),

    func pickerView(pickerView: UIPickerView, viewForRow row: Int, forComponent component: Int, reusingView view: UIView!) -> UIView {
        var view = UIView(frame: CGRectMake(0,0, 150,50))
        let label = UILabel(frame:CGRectMake(0,0, 80, 40))
        view.addSubview(label)
        label.text = array[row]
        return view
    }
    

    The reason you get the error, is because you have two different objects called "view". The one you create inside the if clause is not visible outside that clause, so the "view" you're calling viewWithTag on is the view that's passed in to the method, and that one is always nil.