如圖有一個 TableView,每行顯示這一行是第幾行,現(xiàn)在我希望每按一次 update 按鈕,就動態(tài)地在下方加兩行。那么簡單粗暴的做法是 ,更改數(shù)據(jù)源,然后刷新一下列表:
// tableData = ["0", "1", "2", "3"]
@IBAction func update(_ sender: AnyObject) {
tableData.append("\(tableData.count)")
tableData.append("\(tableData.count)")
tableView.reloadData()
}
用膝蓋想也知道,這會使得前四行沒有被改動的地方也被刷新一遍,帶來了不必要的性能損耗。
好一點的做法是下面這樣的:
// tableData = ["0", "1", "2", "3"]
@IBAction func update(_ sender: AnyObject) {
tableData.append("\(tableData.count)")
tableData.append("\(tableData.count)")
tableView.beginUpdates()
let indexPaths = [IndexPath(row: tableData.count-2, section: 0), IndexPath(row: tableData.count-1, section: 0)]
tableView.insertRows(at: indexPaths, with: UITableViewRowAnimation.automatic)
tableView.endUpdates()
}
與上面相比,這樣做使得 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
方法被少調(diào)用了四次。
這里 beginUpdates
和 endUpdates
方法的作用是,將這兩條語句之間的對 tableView 的 insert/delete 操作聚合起來,然后同時更新 UI。鑒于我這里只進(jìn)行了一次 insert 操作,把這兩條語句去掉也沒事,但是出于規(guī)范還是應(yīng)該寫上,因為假如習(xí)慣不寫,下面這樣的代碼會運行時崩潰:
@IBAction func update(_ sender: AnyObject) {
tableData.append("\(tableData.count)")
tableData.append("\(tableData.count)")
// tableView.beginUpdates()
tableView.insertRows(at: [IndexPath(row: tableData.count-2, section: 0)], with: UITableViewRowAnimation.automatic)
tableView.insertRows(at: [IndexPath(row: tableData.count-1, section: 0)], with: UITableViewRowAnimation.automatic)
// tableView.endUpdates()
}
因為第一次 insert 之后,當(dāng)前 row 的總數(shù)量在 UI 上試圖 4 變成 5,然而數(shù)據(jù)源是 6,它會檢查使用者對 tableView 的 UI 操作,最后是不是和 numberOfRows 方法獲取的值相對應(yīng)。
總結(jié)
numberOfRows 方法調(diào)用: 都只調(diào)用一次 numberOfRows 方法
cellForRow 方法調(diào)用次數(shù): reloadData 會為當(dāng)前顯示的所有cell調(diào)用這個方法,updates 只會為新增的cell調(diào)用這個方法
cellForRow 方法調(diào)用時間: reloadData 會在 numberOfRows 方法調(diào)用后的某一時間異步調(diào)用 cellForRow 方法,updates 會在 numberOfRows 方法調(diào)用后馬上調(diào)用 cellForRow 方法
reloadData 方法缺陷: 帶來額外的不必要開銷,缺乏動畫
updates 方法缺陷:deleteRows 不會調(diào)用 cellForRow 方法,可能導(dǎo)致顯示結(jié)果與數(shù)據(jù)源不一致;需要手動保證 insertRows、deleteRows 之后,row 的數(shù)量與 numberOfRows 的結(jié)果一致,否則會運行時崩潰
部分文章中沒有寫,總結(jié)提到了的部分放在完整 demo 里面了:demo Github 地址