1

I have the following settings tableView:

enter image description here

I want to perform a segue from each of the cells (as indicated by the disclosures) to another view controller. The problem is I don't want to make six different view controllers, especially since many of them will be almost identical, containing one or two text fields and a label. Is there any way I can just make one view controller and change it upon which cell is clicked?

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
Nikhil Sridhar
  • 1,670
  • 5
  • 20
  • 39
  • What is stopping you from creating one view controller and configuring that destination view controller in `prepareForSegue`? – Robotic Cat Mar 11 '17 at 23:50
  • In your `prepareForSegue` method, call `tableVIew.indexPathForSelectedRow` to know what cell was tapped on. Then configure your destination view controller accordingly – Code Different Mar 12 '17 at 02:45

2 Answers2

1

The problem is I don't want to make six different view controllers, especially since many of them will be almost identical, containing one or two text fields and a label.

That's definitely true. You can achieve this by adding only one segue -without the need of adding six different segues- from the settings ViewController to the next one (details ViewController); Based on which row -in which section- has been selected, you can perform to your segue and sending the desired data.

1- Adding Segue:

you need to add a segue from the settings ViewController to the details ViewController. Make sure that the segue has been connected from the settings ViewController itself, but not from any of table view cell. After adding the segue on the storyboard, you need to add an identifier for it, I'll call it -in my code snippet example- "toDetails".

If you don't know how to add an identifier for the segue, you might want to check this answer.

2- Sending Desired Data:

For the purpose of simplifying, I assumed that the data you want to send is just a single string variable, called -in my code snippet example- dataToSend.

It goes as follows:

Settings ViewController:

class SettingsViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
@IBOutlet weak var tableView: UITableView!

//...
private var dataToSend = ""
//...

//...
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
    performSegue(withIdentifier: "toDetails", sender: self)
}
//...

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

    // tableView should be connected as an IBOutlet
    guard let selectedIndexPath = tableView.indexPathForSelectedRow else {
        print("Something went wrong when selected a row!")
        return
    }

    if selectedIndexPath.section == 0 { // Account Section

        if selectedIndexPath.row == 0 { // Name Row
            dataToSend = "name"
        } else if selectedIndexPath.row == 1 { // School Row
            dataToSend = "school"
        } else if selectedIndexPath.row == 2 { // Grade Row
            dataToSend = "grade"
        }

    } else if selectedIndexPath.section == 1 { // Private Section

        if selectedIndexPath.row == 0 { // Email Row
            dataToSend = "email"
        } else if selectedIndexPath.row == 1 { // Password Row
            dataToSend = "password"
        } else if selectedIndexPath.row == 2 { // Phone Number Row
            dataToSend = "phone"
        }

    }

    let detailsViewController = segue.destination as! DetailsViewController
    detailsViewController.receivedData = dataToSend
    }

    //...
}

Take it Further:

It is a good practice when working with such a case to use enums instead of checking rows numbers, that leads to more readable code:

enum Sections:Int {
    case
    account = 0,
    privacy = 1
}

enum AccountRows:Int {
    case
    name = 0,
    school = 1,
    grade = 2
}

enum PrivacyRows:Int {
    case
    email = 0,
    password = 1,
    phone = 2
}

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    //...
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {

        // tableView should be connected as an IBOutlet
        guard let selectedIndexPath = tableView.indexPathForSelectedRow else {
            print("Something went wrong when selected a row!")
            return
        }

        // tuple of (section, row)
        switch (selectedIndexPath.section, selectedIndexPath.row) {
            // Accounts Section
            case (Sections.account.rawValue, AccountRows.name.rawValue):
                dataToSend = "name"
            case (Sections.account.rawValue, AccountRows.school.rawValue):
                dataToSend = "school"
            case (Sections.account.rawValue, AccountRows.grade.rawValue):
                dataToSend = "grade"

            // Privacy Section
            case (Sections.privacy.rawValue, PrivacyRows.email.rawValue):
                dataToSend = "email"
            case (Sections.privacy.rawValue, PrivacyRows.password.rawValue):
                dataToSend = "password"
            case (Sections.privacy.rawValue, PrivacyRows.phone.rawValue):
                dataToSend = "phone"
            default:
                print("Something went wrong when checking Section and Rows!")
        }

        let detailsViewController = segue.destination as! DetailsViewController
        detailsViewController.receivedData = dataToSend
    }
    //...
}

Cheers up! Hope this helped.

Ahmad F
  • 30,560
  • 17
  • 97
  • 143
0
Create a new View Controller i am naming it as "VController"

Create enum in "VController" above the view didload :

  public enum VCType:Int {
        case  name = 1
        case school = 2
        case grade = 3
    }
    var selectedVc:VCType!

In viewdidload of "VController":

 if selectedVc == .name {
            // do whatever you want
        }
        else if selectedVc == .school {
            // do whatever you want
        }
        else if
        ..........
        ..........


Code For First ViewController :

above the view didload :

 var selectedType:VController.VCType!


    // in didSelectRowAtIndexPath
     selectedType = .school // if selecting school
     perform segue


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
            if segue.identifier == "mySegue"{
                let nextScene = segue.destination as? VController
                nextScene?.selectedVc = selectedType
            }
        }
Jagdeep Singh
  • 2,556
  • 3
  • 18
  • 28