DJ-Glock
DJ-Glock

Reputation: 1411

Issue with setting selectedRow for UIPicker

I have an issue with setting initial value for UIPicker. I have: UIPicker in my storyboard. Connected to TableViewController (I have static table) class as IBOutlet:

enter image description here

class SettingsTableViewController: UITableViewController, UIPickerViewDelegate, UIPickerViewDataSource {
    //Variables
    let pricePerHour: Float = 0
    let defaults = UserDefaults.standard
    let currencies = ["USD", "RUR", "UAH", "BYN", "NIS"]

    //IBOutlets
    @IBOutlet weak var isTimeCafeSwitch: UISwitch!
    @IBOutlet weak var pricePerHourTextField: UITextField!
    @IBOutlet var currencyPicker: UIPickerView!

I used this answer as an example for setting initial value. But I am getting NSRangeException because I suppose that I'm trying to set value for UI picker before it was fully initialized. I have added some prints into my code to show the issue:

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

func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
    print("Picker view initialized - getting number of rows")
    return currencies.count
}

func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
    return currencies[row]
}

func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {
    defaults.set(currencies[row], forKey: "currency")
    print(GenericStuff.currency)
}


//System functions for view
override func viewDidLoad() {
    print("View did load")
    currencyPicker.dataSource = self
    currencyPicker.delegate = self

    //To dismiss keyboard
    self.view.addGestureRecognizer(UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing(_:))))
}

override func viewWillAppear(_ animated: Bool) {
    print("View will appear")

    //Set value for currency picker
    currencyPicker.selectedRow(inComponent: currencies.index(of: GenericStuff.currency)!)
    print("Tried to set selectedRow")

    pricePerHourTextField.text = String(describing: defaults.float(forKey: "pricePerMinute"))
    isTimeCafeSwitch.isOn = defaults.bool(forKey: "isTimeCafe")
}

And here is my output:

View did load
View will appear
Picker view initialized - getting number of rows
Picker view initialized - getting number of rows
Picker view initialized - getting number of rows
Picker view initialized - getting number of rows
2017-07-20 01:20:42.163 CafeManager[8135:265457] *** Terminating app due to uncaught exception 'NSRangeException', reason: '*** -[__NSArrayM objectAtIndex:]: index 4 beyond bounds [0 .. 0]'

So as I can see the sequence is:

viewDidLoad is called - here I set delegate and datasource.

viewWillAppear is called - here I tried to setSelected for UIPicker

UIPicker started initialization.

It looks like I have concurrency issue here, but not sure how to fix it properly. And I really wonder how it worked in mentioned example. Tried to put selectedRow to viewDidLoad - same result.

Upvotes: 1

Views: 435

Answers (1)

DJ-Glock
DJ-Glock

Reputation: 1411

Okay, I've found the reason: Do not write code in the night.

I have used wrong function. I used:

currencyPicker.selectedRow(inComponent: currencies.index(of: GenericStuff.currency)!)

Instead of:

currencyPicker.selectRow(currencies.index(of: GenericStuff.currency)!, inComponent: 0, animated: true)

And it works fine.

Upvotes: 5

Related Questions