Search code examples
iosswiftuipickerviewuisegmentedcontrol

PickerView - How to return 2 different array based on a segmented Control selection


In my app I have a text field (Distance) that has segmented control to choose the unit reference (Km/Mi):

enter image description here

I have another text field (pace) that show a UIPickerView. This picker view can be populated with 2 arrays based on what unit the user selected. Everything works except that, even when the picker view is not shown and I change the selection, the array change only when I start scroll the picker view. So initially it shows the array in km even if I selected Mi and then it changes when I start moving the picker.

Initially I set a variable for the unit reference and the 2 arrays

var unitReference = "Km" // this is the initial selection on the segmented control 
let paceKmArray = [" ", "Relaxing(less than 15km/h)", "Easy(15km/h-20km/h)","Medium(20km/h-25km/h)","Nice(25km/h-30km/h)","Fast(30km/h-35km/h)", "Very Fast(>35km/h)"]
let paceMiArray = [" ", "Relaxing(less than 10 mi/h)", "Easy(10mi/h-13mi/h)","Medium(13mi/h-16mi/h))","Nice(16mi/h-19mi/h))","Fast(19mi/h-12mi/h))", "Very Fast(>22mi/h)"]

then in viewDidLoad

unitReferenceSegmentedControl.addTarget(self, action: "unitChanged:", forControlEvents: .ValueChanged);

which call this method to changed the unit reference

func unitChanged(sender:UISegmentedControl){

    if sender.selectedSegmentIndex == 0{
        unitReference = "Km"
        print(unitReference)

    }

    if sender.selectedSegmentIndex == 1{

        unitReference = "Mi"

        print(unitReference)    
    }
}

And the picker view methods

func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int {

    return 1

}

func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {

    if pickerView.tag == 0{
        return rideTypeArray[row]
    }

    if pickerView.tag == 1{
        if unitReference == "Km"{

        return paceKmArray[row]
        }
        if unitReference == "Mi"{

         return paceMiArray[row]
        }
    }

        return ""

}

func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int{

    if pickerView.tag == 0{

    return rideTypeArray.count
    }
    if pickerView.tag == 1{

        if self.unitReference == "Km"{

            return paceKmArray.count
        }
        if self.unitReference == "Mi"{

            return paceMiArray.count
        }


    }
    return 0
}

func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int)
{

    if pickerView.tag == 0{
        rideTypeTextField.text = rideTypeArray[rideTypePickerView!.selectedRowInComponent(0)] as String   

    }

    if pickerView.tag == 1{

        if unitReference == "Km"{

            paceTextField.text = paceKmArray[pacePickerView!.selectedRowInComponent(0)] as String
        }
        if unitReference == "Mi"{

            paceTextField.text = paceMiArray[pacePickerView!.selectedRowInComponent(0)] as String
        }     

    }

}

I am not sure this is the best way to do it. If there is a more elegant way to do it, I will be more than happy to learn it.


Solution

  • You are not seeing the changes in your picker view because you are not reloading the data after the datasource is changed. Just call reloadAllComponents on your pickerView once you have changed the datasource and you are good to go.

    func unitChanged(sender:UISegmentedControl) {
        //Your previous code for changing the datasource array.
    
        //Now reload the UIPickerView
        pacePickerView.reloadAllComponents()
    }
    

    One more suggestion i would like to give is that if in both the datasource array's have same set of key value pairs then you should keep a 3rd array as the ultimate datasource and switch it with the respective arrays from your unitChanged: method. That way you won't need to have an if condition every now and then to get the current set of data.