filterTableViewController.reloadRows reloading row

2019-06-02 07:51发布

I have a table with 3 rows each with check button.What I am doing is when I select all the three buttons I want to click my cancel button which is on view not table on same controller to reload all 3 rows the call goes to custom cell class where uncheck is set to true and rows are reloaded.For the first attempt it works fine I can see correct index to be reloaded.On the second time again when I select all 3 check buttons and click cancel again I can see correct index to be reloaded but the call is not going to custom cell class again the check box still remains checked.Any idea why? I am always getting correct index in my array.

Cancel button code-:

@IBAction func cancelDataItemSelected(_ sender: UIButton) {
    for index in selectedButtonIndex{
            let indexPath = IndexPath(item: index, section: 0)
            print(selectedButtonIndex)
            filterTableViewController.reloadRows(at: [indexPath], with: UITableViewRowAnimation.none)
    }
    selectedButtonIndex .removeAll()
    print(selectedButtonIndex)
}

Table code-:

extension filterControllerViewController:UITableViewDataSource,UITableViewDelegate
{
    // NUMBER OF ROWS IN SECTION
     func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int{
      return ControllerData.count
     }

    // CELL FOR ROW IN INDEX PATH
     func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
     let Cell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! ControllerCellTableViewCell
    Cell.filterTableMenu.text = ControllerData[indexPath.item]
     Cell.radioButtonTapAction = {
     (cell,checked) in
     if let radioButtonTappedIndex =  tableView.indexPath(for: cell)?.row{
        if checked == true {
          self.selectedButtonIndex.append(radioButtonTappedIndex)
    }
        else{
            while self.selectedButtonIndex.contains(radioButtonTappedIndex) {
                if let itemToRemoveIndex = self.selectedButtonIndex.index(of: radioButtonTappedIndex) {
                    self.selectedButtonIndex.remove(at: itemToRemoveIndex)
                 }
              }
           }
        }
    }
     return filterCell
}

Custom Class-:

var radioButtonTapAction : ((UITableViewCell,Bool)->Void)?
     //MARK-:awakeFromNib()
        override func awakeFromNib() {
            super.awakeFromNib()
            filterTableSelectionStyle()
            self.isChecked = false
        }

        // CHECKED RADIO BUTTON IMAGE
        let checkedImage = (UIImage(named: "CheckButton")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal))! as UIImage
        // UNCHECKED RADIO BUTTON IMAGE
        let uncheckedImage = (UIImage(named: "CheckButton__Deselect")?.withRenderingMode(UIImageRenderingMode.alwaysOriginal))! as UIImage
        // Bool STORED property
        var isChecked: Bool = false {
            didSet{
                // IF TRUE SET TO CHECKED IMAGE ELSE UNCHECKED IMAGE
                if isChecked == true {
                  TableRadioButton.setImage(checkedImage, for: UIControlState.normal)
                } else {
                  TableRadioButton.setImage(uncheckedImage, for: UIControlState.normal)
                }
            }
        }
        // FILTER CONTROLLER RADIO BUTTON ACTION

        @IBAction func RadioButtonTapped(_ sender: Any) {
            isChecked = !isChecked
            radioButtonTapAction?(self,isChecked)
        }

2条回答
我命由我不由天
2楼-- · 2019-06-02 08:21

Fundamental misunderstanding of how "reusable" table cells work.

Let's say your table view is tall enough that only 8 cells are ever visible. It seems obvious that 8 cells will need to be created, and they will be reused when you scroll.

What may not be obvious is that the cells also are reused when they are reloaded. In other words, every time .reloadData is called - even if you are only reloading one cell that is currently visible - that cell is reused. It is not re-created.

So, the key takeaway point is: Any initialization tasks happen only when the cell is first created. After that, the cells are reused, and if you want "state" conditions - such as a checked or unchecked button - it is up to you to "reset" the cell to its original state.

As written, your cellForRowAt function only sets the .filterTableMenu.text ... it ignores the .isChecked state.

You can mostly fix things just by setting the cell's .isChecked value, but you're also tracking the on/off states in a much more complicated manner than need be. Instead of using an Array to append / remove row indexes, use an Array of Booleans, and just use array[row] to get / set the values.

Then your cellForRowAt function will look about like this:

// CELL FOR ROW IN INDEX PATH
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let filterCell = tableView.dequeueReusableCell(withIdentifier: "filterCell", for: indexPath) as! ControllerCellTableViewCell

    // set the label in filterCell
    filterCell.filterTableMenu.text = ControllerData[indexPath.item]

    // set current state of checkbox, using Bool value from out "Tracking Array"
    filterCell.isChecked = self.selectedButtonIndex[indexPath.row]

    // set a "Callback Closure" in filterCell
    filterCell.radioButtonTapAction = {
        (checked) in
        // set the slot in our "Tracking Array" to the new state of the checkbox button in filterCell
        self.selectedButtonIndex[indexPath.row] = checked
    }

    return filterCell

}

You can see a working example here: https://github.com/DonMag/CheckBoxCells

查看更多
淡お忘
3楼-- · 2019-06-02 08:25

Remember that the cells are reused and that reloadRows just tells the rows to redraw. When a checkbox in a cell is checked by the user, the new checked state should be saved in the underlying data source, and the state marked in the cell in cellForRowAtIndexPath. Otherwise the cell checkbox shows the state for the last time it was set by the user for all indices and not the state for the underlying data source.

查看更多
登录 后发表回答