You need to do a couple things...
- use a data structure - likely an array of custom objects - to track the "selected" state
- set the
.accessoryType
for the cell in cellForRowAt
- pass an array of selected rows (selected objects) to the next view controller
Here is a very simple example. In your Storyboard, add a UITableViewController
, set its custom class to TestTableViewController
and embed it in a UINavigationController
.
When you run this, you can select - that is, add checkmarks - to multiple rows.
When you tap the "Test" button in the navigation bar it will push to SampleViewController
which will display the selected row titles in a label.
When you go "Back" your data will be retained, and the correct rows will have checkmarks.
struct MyDataStruct {
var title: String = ""
var isSelected: Bool = false
}
class TestTableViewController: UITableViewController {
var myData: [MyDataStruct] = [
MyDataStruct(title: "One", isSelected: false),
MyDataStruct(title: "Two", isSelected: false),
MyDataStruct(title: "Three", isSelected: false),
MyDataStruct(title: "Four", isSelected: false),
MyDataStruct(title: "Five", isSelected: false),
MyDataStruct(title: "Six", isSelected: false),
MyDataStruct(title: "Seven", isSelected: false),
MyDataStruct(title: "Eight", isSelected: false),
MyDataStruct(title: "Nine", isSelected: false),
MyDataStruct(title: "Ten", isSelected: false),
MyDataStruct(title: "Eleven", isSelected: false),
MyDataStruct(title: "Twelve", isSelected: false),
MyDataStruct(title: "Thirteen", isSelected: false),
MyDataStruct(title: "Fourteen", isSelected: false),
MyDataStruct(title: "Fifteen", isSelected: false),
MyDataStruct(title: "Sixteen", isSelected: false),
MyDataStruct(title: "Seventeen", isSelected: false),
MyDataStruct(title: "Eighteen", isSelected: false),
MyDataStruct(title: "Nineteen", isSelected: false),
MyDataStruct(title: "Twenty", isSelected: false),
]
override func viewDidLoad() {
super.viewDidLoad()
tableView.register(UITableViewCell.self, forCellReuseIdentifier: "TableViewCell")
let b = UIBarButtonItem(title: "Test", style: .plain, target: self, action: #selector(barButtonTapped(_:)))
self.navigationItem.rightBarButtonItem = b
}
@objc func barButtonTapped(_ sender: Any?) -> Void {
// instantiate the next view controller
let vc = SampleViewController()
// filter myData to only the elements with isSelected = true
let selectedItems = myData.filter{ $0.isSelected == true }
// set the next VC's property (i.e. pass the data to it)
vc.theSelectedRows = selectedItems
// push to the next VC
self.navigationController?.pushViewController(vc, animated: true)
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return myData.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath)
let dataElement: MyDataStruct = myData[indexPath.row]
cell.textLabel?.text = dataElement.title
cell.accessoryType = dataElement.isSelected ? .checkmark : .none
return cell
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// toggle selected state in data
myData[indexPath.row].isSelected = !myData[indexPath.row].isSelected
tableView.reloadRows(at: [indexPath], with: .automatic)
}
}
class SampleViewController: UIViewController {
var theSelectedRows: [MyDataStruct] = [MyDataStruct]()
override func viewDidLoad() {
super.viewDidLoad()
view.backgroundColor = .white
let resultLabel: UILabel = UILabel()
view.addSubview(resultLabel)
resultLabel.translatesAutoresizingMaskIntoConstraints = false
resultLabel.numberOfLines = 0
var s = ""
theSelectedRows.forEach { d in
s += d.title + "\n"
}
resultLabel.text = s
resultLabel.centerXAnchor.constraint(equalTo: view.centerXAnchor).isActive = true
resultLabel.centerYAnchor.constraint(equalTo: view.centerYAnchor).isActive = true
}
}
Output:

