Search code examples
iosswiftsegue

Passing data between Swift view controllers not working on first segue transition


I have a Swift file containing four separate arrays of tuples. In ViewControllerA I have four different buttons, each of which changes the value of "selectedPosition" and is set to trigger "SegueAtoB". "selectedPosition" should then be used in ViewControllerB to select the appropriate array to populate a UIPickerView on ViewControllerB.

Currently, my prepare for segue method only passes the correct data the second time a button is pressed, e.g. when the app loads into ViewControllerA I press a button, it takes me to ViewControllerB, but the array selected for the UIPickerView is the default, when I dismiss back to ViewControllerA and press a button, the code works as it should.

ViewControllerA :

class ViewControllerA: UIViewController {

    // Variable to hold position selected (passed through to ViewControllerB)
    var selectedPosition : String = ""


    // Button1
    // Set up to run "SegueAtoB"
    @IBOutlet weak var selectButton_CEO: UIButton!
    @IBAction func selectButton_CEO_Tapped(_ sender: UIButton) {
        selectedPosition = "CEO"
    }


    // MARK: - Navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "SegueAtoB" {
            let VC : ViewControllerB = segue.destination as! ViewControllerB
            VC.ReceivePlayerDataDelegate = self
            VC.currentPosition = selectedPosition
        }
    }

}

ViewControllerB :

class ViewControllerB: UIViewController, UIPickerViewDataSource, UIPickerViewDelegate {


    // set the position passed through from ViewControllerB
    var currentPosition : String = ""

    // set the playersArray by position
    var posArray = ceoArray


    // Button to dismiss ViewControllerB
    @IBAction func closeButton(_ sender: UIButton) {
        dismiss(animated: true, completion: nil)
    }


    // Picker view
    @IBOutlet weak var posPickerView: UIPickerView!


    override func viewDidLoad() {
        super.viewDidLoad()

        // select appropriate array based on position selected
        selectArray(currentPos: currentPosition)

        // Delegate picker view to self
        posPickerView.delegate = self
        posPickerView.dataSource = self

    }


    // UIPickerViewMethods
    // Set the number of picker columns to 1
    func numberOfComponents(in pickerView: UIPickerView) -> Int {
        return 1
    }

    // Set the number of picker rows to the number of items in posArray
    func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int {
        return posArray
    }

    // Set the title of each picker row to each name in posArray
    func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? {
        return posArray[row].name
    }


    // Picker action
    // What happens when selection is made
    func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) {

        print(posArray[row])

        // I've removed what's in here as it's not relevant to the question

    }


    // Method to select correct array based on currentPosition -- called in viewDidLoad
    func selectArray(currentPos: String) {

        switch (currentPos) {
        case "CEO" :
            posArray = ceoArray
        case "CFO" :
            posArray = cfoArray
        default :
            posArray = ceoArray
        }

    }


}

I need the UIPickerView to be updated to the relevant array on the first segue from ViewControllerA to ViewControllerB, not resorting to default on the first segue.


Solution

  • If multiple controls result in the same segue, you need to check the sender in the prepare(for:) function. If it was the CEO button, set the CEO string etc.:

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        guard segue.identifier == "SegueAtoB",
              let vc = segue.destination as? ViewControllerB,
              let senderButton = sender as? UIButton   else { return }
    
        vc.ReceivePlayerDataDelegate = self
        if (senderButton === selectButton_CEO) {
            vc.currentPosition = "CEO"
        } else if (senderButton === selectButton_CFO) {
            vc.currentPosition = "CFO"
        } // and so on
    }