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