迭代TableViewCells会跳过一些

时间:2017-08-01 17:29:32

标签: ios swift cocoa-touch

我有一个tableview,每个单元格中都有一个复选框。我还有一个"选择全部"按钮。

我的问题是,当我单击选择所有我要更新所有复选框以检查状态。因此,从100个单元格的列表中,所有都被检查,但每个第13个单元格都没有。为了更清楚,在我的模拟器屏幕上可以看到12个单元格,所有单元格都被检查。当我开始滚动时,出现的第一个单元格未经检查,然后是12个已检查的单元格:S 当我滚动一点然后点击"选择所有"再次,跳过的那些也被检查..

任何人都知道我错过了什么?

这是单元格代码:

class ListTableViewCell: UITableViewCell {

@IBOutlet weak var checkbox: UIButton!
var buttonState = false{
    didSet{
        if buttonState{
            checkbox.setImage(#imageLiteral(resourceName: "checked"), for: .normal)
        }else{
            checkbox.setImage(#imageLiteral(resourceName: "unchecked"), for: .normal)
        }
    }
}

@IBAction func checkboxAction(_ sender: UIButton) {

    if buttonState {
        buttonState = false                                  
    }else{
        buttonState = true
    }
}

func simulateCheck(){
    buttonState = true
 }

以下是我控制器的一些snipets:

 private var articleValues: [ArticleValue] = []{
    didSet{
        tableView.reloadData()

    }
}
func selectAll(){

    for i in 0..<articleValues.count{            
        let cell = tableView.cellForRow(at: IndexPath(item: i, section: 0)) as? ListTableViewCell
        cell?.simulateCheck()
        tableView.reloadData()          
    }   
}


func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "articleValueItem", for: indexPath)

    // Cell Configuration
    let articleValue = articleValues[indexPath.row]
    if let articleValueCell = cell as? ListTableViewCell{
        articleValueCell.articleValue = articleValue
    }
    return cell
}

2 个答案:

答案 0 :(得分:1)

您的UITableView由数据源支持。这意味着您不应该像在此处那样直接更改单元格:

cell?.simulateCheck()
tableView.reloadData()          

相反,您应该保留所有已检查位置的列表,也许是另一个对应每个对应articleValue具有bool的数组(这不是最佳设计)。

var checkedValues = Bool

在你的 然后,您将设置func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell方法,以设置单元格的状态:

articleValueCell.buttonState = checkedValues[indexPath.row]

在您的selectAll方法中,使用true值填充此数组,然后调用tableView.reloadData()

private var checkedValues = [Bool]()
private var articleValues: [ArticleValue] = []{
    didSet{
        checkedValues = Array(repeating: false, count: articleValues.count)
        tableView.reloadData()
    }
}

func selectAll(){
    checkedValues = Array(repeating: true, count: articleValues.count)
    tableView.reloadData()
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "articleValueItem", for: indexPath)

    // Cell Configuration
    let articleValue = articleValues[indexPath.row]
    if let articleValueCell = cell as? ListTableViewCell{
        articleValueCell.articleValue = articleValue
        articleValueCell.buttonState = checkedValues[indexPath.row]
    }
    return cell
}

另一个错误是你不应该迭代表中的所有单元格,因为它们被重用,没有必要通过你的数据源并为每个单元格获取一个单元格。迭代tableView.visibleCells才有意义。但就像你的情况一样,大多数时候你也不需要,你应该相应地更新你的数据源并重新加载表或只是修改过的单元格。

答案 1 :(得分:0)

不建议您直接在表格视图中引用单元格。原因是UITableViews有一种有效的方法,只需要在需要时加载单元格(并在不再需要它们时解除分配,例如单元格滚出屏幕)。因此,您尝试引用的单元格可能无法加载。

相反,您应该通过cellForRowAt方法与其进行互动。如果要“选择所有”单元格,则应创建一个属性,通过checked存储not checkedBool的值,然后设置所有ArticleValue元素到该属性的true并重新加载selectAll()内的数据。

它可以像这样工作:

func selectAll() {
    articleValues.forEach {
        $0.checked = true
    }

    tableView.reloadData()
}

// ...

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

    let cell = tableView.dequeueReusableCell(withIdentifier: "articleValueItem", for: indexPath)

    // Cell Configuration
    let articleValue = articleValues[indexPath.row]
    if let articleValueCell = cell as? ListTableViewCell{
        articleValueCell.articleValue = articleValue

        if articleValue.checked {
            articleValueCell.simulateCheck()
        }
    }

    return cell
}