prepare for segue call before tableView didSelectRowAt indexPath iOS

300 Views Asked by At

I have 3 VC - VC1, VC2 & VC3

I'm creating an unwind segue where -

  1. VC1 is destination
  2. VC2 is source

So, I've add Marker function in VC1 -

@IBAction func unwindToHomeViewController(_ sender: UIStoryboardSegue) {}

and in VC2 I've created two variable -

var userSelectedPlacesLatitude: Double = 0
var userSelectedPlacesLongitude: Double = 0

which will be updated in tableView -

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    self.userSelectedPlacesLatitude = suggestedPlacenames[indexPath.row].geometry.coordinates[1]
    self.userSelectedPlacesLongitude = suggestedPlacenames[indexPath.row].geometry.coordinates[0]
    print("In didSelectRowAt", userSelectedPlacesLatitude, userSelectedPlacesLongitude)
}

and then prepare for segue -

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    let destinationVC = segue.destination as! VC1
    print("In Segue preperation",userSelectedPlacesLatitude, userSelectedPlacesLongitude)
    destinationVC.userSelectedPlacesLatitude = self.userSelectedPlacesLatitude
    destinationVC.userSelectedPlacesLongitude = self.userSelectedPlacesLongitude
    destinationVC.reloadWeatherDataStatus = true
}

But from print value I'm seeing that prepareforSegue is called earlier than didSelectRowAt. Hence I'm not getting expected value in prepareforsugue

In Segue preperation 0.0 0.0
In didSelectRowAt 49.3227937844972 31.3202829593814

Hence 0.0 0.0 is passing all the time to VC1. How can I fix this problem?

2

There are 2 best solutions below

0
Paulw11 On BEST ANSWER

The problem you are experiencing results from having at the unwind segue linked directly from the table view cell in your storyboard. As soon as the user taps the row, the unwind segue fires. The didSelectRow(at:) function is called after, but this is too late; You are already back in VC1.

While you can use prepareForSegue to send data to VC1, a better approach is to use the sender passed to unwindToHomeViewController to let VC1 get the data from VC2.

This means that VC2 doesn't need to know anything about VC1. You can also get rid of the reloadWeatherDataStatus property and simply reload the weather data status in the unwind function.

You should:

  • Remove the segue from the table view row in VC2
  • In your storyboard, ctrl-drag from the "View controller" icon at the top of VC2 to the "Exit" icon at the top of VC2 and select unwindToHomeViewController
  • Select the newly created unwind segue and give it an identifier, say unwindToVC1
  • In VC2 you have
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    self.userSelectedPlacesLatitude = suggestedPlacenames[indexPath.row].geometry.coordinates[1]
    self.userSelectedPlacesLongitude = suggestedPlacenames[indexPath.row].geometry.coordinates[0]
    self.performSegue(withIdentifier:"unwindToVC1", sender: self)
}
  • Remove prepare(for segue: sender:) from VC2

  • In VC1

@IBAction func unwindToHomeViewController(_ sender: UIStoryboardSegue) {
    if let sourceVC = sender.source as? VC2 {
        self.userSelectedPlacesLatitude = sourceVC.userSelectedPlacesLatitude
        self.userSelectedPlacesLongitude = sourceVC.userSelectedPlacesLongitude
        // Do whatever is required to reload the data based on the new location
    }
}
5
Prateek Varshney On

Try the code below and let me know if it works -

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    let destinationVC = VC1()
    destinationVC.userSelectedPlacesLatitude = suggestedPlacenames[indexPath.row].geometry.coordinates[1]
    destinationVC.userSelectedPlacesLongitude = suggestedPlacenames[indexPath.row].geometry.coordinates[0]
    destinationVC.reloadWeatherDataStatus = true
    destinationVC.performSegueWithIdentifier("DestinationSegueName", sender: self)
}

Adding modifications to this answer since some people might have problems with creating the VC instance -

Step 1 - Create a manual segue named "SegueToDestinationVc" from source(VC1) to destination(VC2) view controller and write this code in source view controller -

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if (segue.identifier == "SegueToDestinationVc") {
        let vc = segue.destination as! VC2
        vc.dataToPass = someData
    }
}

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    someData = placeName[indexPath.row]
}

Step 2 - In destination view controller(VC2) has a public property named "dataToPass" and use it.

Happy to help, Thanks.

Happy Coding

Let me know if you need any other help.