2017-08-01 94 views
1

我有一个tableview,并在每个单元格中有一个复选框。我也有一个“全选”按钮。迭代通过TableViewCells跳过一些

我的问题是,当我点击选择所有我想更新所有复选框到选中状态。所以从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

为什么不在'articleValues'数组中创建一个属性来检查该项目以及何时重新载入数据(如果在“cellForRowAt”中选中)。不建议直接与单元交互,而是使用数据源。 – GIJOW

+1

我想在你的selectAll()函数中,我会在这个函数的最后调用reloadData()。另外,为什么不在'cellForRowAt'函数中返回'articleValueCell'? – antonio081014

+0

GIJOW大声思考,articleValues连接到数据库,并且我认为将复选框状态保存到数据库不是一个好主意。也许虽然元组或字典可以做到这一点? antonio081014你的第一点是完全正确的性能问题,我想,但我不认为这是问题。你的第二点......我不知道为什么!感谢您指出。 – Thodoris

回答

1

UITableView由数据源的支持。这意味着,像你在这里做的,你不能改变细胞直接:

cell?.simulateCheck() 
tableView.reloadData()   

相反,你应该把所有的检查位置,也许这​​对每个相应articleValue的bool另一个数组列表(这是不是最好的设计)。

VAR checkedValues =布尔

在你 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 
} 

另一个错误是,你应该neve r遍历表中的所有单元格,因为它们被重用,没有必要通过数据源并为每个单元格获取单元格。通过遍历tableView.visibleCells才有意义。但就你的情况而言,大多数情况下你也不需要,你应该相应地更新你的数据源并重新加载表格或者修改后的单元格。

+0

像魅力一样工作。你仍然提到这不是最好的设计。你会有另一个建议,还是你可以更具体一些? – Thodoris

+1

也许将标记存储在'Dictionary'而不是'Array'中,并且作为一个键使用'articleValue'中的某种ID,或者整个'articleValue'对象(但是必须使其成为'Hashable'为了这) – Levi

0

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

相反,您应该通过cellForRowAt方法与它进行交互。如果要“选择所有”单元格,则应通过Bool创建一个存储值checkednot checked的属性,然后将该属性的所有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 
} 
+0

感谢您的回答。问题是我的数据保存在数据库中,也发送到服务器,因此我想避免直接将这些功能添加到我的对象中。 – Thodoris