0

Right now, I'm able to select all rows visible on the screen, but I want to be able to select all rows in the TableView including off-screen rows.

I've tried the extension here: programmatically select all cells in tableview so next time they are pressed they call didDeselect

As well as second solution here: Select ALL TableView Rows Programmatically Using selectRowAtIndexPath

Both end with the same results, only visible rows being selected.

My end goal is, when I'm able to select all rows, I can then press my "Acknowledge" button and that retrieves an ID for each row, then sends it to the server, which I'm already able to accomplish, I just need to figure out how to select ALL rows so I can get that list of IDs.

Thanks for the help!

Added Data source structure

var dataClassArr = [DataClass]()

struct DataClass: Codable {
    let id: String
}
J. Doe43
  • 207
  • 2
  • 6
  • 20

2 Answers2

1

You don't.

You can't select all cells because they're being reused, which means only enough cells exist.

When the "Acknowledge" button is pressed, you can get the data from your datasource, the one you're consuming to create your UITableView.


Note: If there is a state change when that button is pressed, you should iterate through your datasource and update your objects. And then you .reloadData().


Updates based on your question update, this is how you iterate through your datasource.

        var dataClassArr = [DataClass]()

        var result = [String]()

        dataClassArr.append(DataClass(id: "1"))
        dataClassArr.append(DataClass(id: "42")) // just for example, you should remove those.

        for element in dataClassArr {
            result.append(element.id)
        }

        print(result) // ["1", "42"] -> based on example values.
Gustavo Vollbrecht
  • 3,188
  • 2
  • 19
  • 37
  • Thanks for the advice, I'll go ahead and give that a shot! – J. Doe43 Apr 17 '19 at 17:44
  • Hmm, I can't seem to figure out how to access my Codable struct to access all of the IDs. How would I go about doing that? I'll update my question with my struct shortly. – J. Doe43 Apr 17 '19 at 21:13
  • it's `dataClassArr`, what do you want to send to your backend? You can create a `[String]()` and iterate through `dataClassArr`, appending each id as String. – Gustavo Vollbrecht Apr 17 '19 at 21:22
  • Yeah, that's exactly what I want, but how would I iterate through dataClassArr since it's Codable? I found example for structs without Codable, tried those and didn't work. – J. Doe43 Apr 17 '19 at 21:25
  • Thank you very much! That is exactly what I needed! – J. Doe43 Apr 17 '19 at 22:08
0

Suppose your UITableView's data source is

struct Item {
    id: Int
}
var dataSource: [Item] = []

You should select all ids from above data source, like so:

let result = dataSource.map{ $0.id }

If you need to change the user interface to select UITableViewCells, you have to create a new property isSelected in your struct, because you cannot change selection state of a UITableViewCell that is not visible, so begin by adding the new property:

struct Item {
    id: Int
    var isSelected = false
}

Now you will use above data source to change the selection state, like so

class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {

    @IBOutlet weak var tableView: UITableView!

    private var dataSource = [Item]()

    override func viewDidLoad() {
        super.viewDidLoad()

        self.navigationItem.leftBarButtonItem = UIBarButtonItem(title: "Toggle", style: .plain, target: self, action: #selector(selectAllAction))
        self.navigationItem.rightBarButtonItem = UIBarButtonItem(title: "Acknowledge", style: .plain, target: self, action: #selector(acknowledgeAction))

        self.tableView.allowsMultipleSelection = true
        self.tableView.dataSource = self
        self.tableView.delegate = self
    }

    @objc func selectAllAction() {
        let totalRows = self.dataSource.count
        let isSelectAll = self.dataSource.first(where: { !$0.isSelected }) != nil
        for index in 0..<totalRows {
            self.dataSource[index].isSelected = isSelectAll
        }
        self.tableView.visibleCells.forEach {
            $0.setSelected(isSelectAll, animated: true)
        }
    }

    @objc func acknowledgeAction() {
        let result = self.dataSource.compactMap{ $0.isSelected ? $0.id : nil }
        print(result)

        guard !result.isEmpty else { return }

        // send selected id(s) to the server
    }

    func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        cell.isSelected = self.dataSource[indexPath.row].isSelected
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        self.dataSource[indexPath.row].isSelected = true
    }

    func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
        self.dataSource[indexPath.row].isSelected = false
    }

}
AamirR
  • 11,672
  • 4
  • 59
  • 73