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.