2017-08-01 93 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