在把data放進table之前,先跟大家講解一個重要的觀念:reuse。
在沒有reuse之前,一筆資料一個row就開一個cell,但如果有1000筆資料怎麼辦?開1000個cell非常的浪費記憶體空間,同時也影響了app的效能。工程師就想到:反正我開1000個cell,螢幕也無法同時顯示這麼多個,那不如讓cell可以被重複利用。
於是就想出下圖這個方法:
(圖片來源:iOS Performance Tricks To Make Your App Feel More Performant)
當手機螢幕上下滑動,沒入螢幕邊緣的cell就會進到一個佇列裡,而同時間會從佇列叫出cell供滑動出現的表格列使用。
這麼一來cell就可以被重複使用,即便我有1000筆資料,也只需要準備與手機螢幕符合的cell數量即可,而關於這點你只要呼叫相對應的function,符合螢幕的cell數swift自己會幫你handle。
接下來來講講怎麼把資料裝進table裡。
要把資料裝進table,首先要設計一個cell,並且可以供table使用。
swift提供了register(_:forCellReuseIdentifier:)這個方法,讓你可以依據cell的名字註冊一個cell給table,而可以被註冊的只有:
之前範例看到的不同形式的cell,其實就是UITableViewCell裡面提供的內建形式,現在我們來實作看看。
首先創建一個UITableViewCell的子類別。
接下來設計cell裡面的格式,我們加了一個image和一個label,並把它取名叫adventureCell,這部分因為與UITableView裡的function不相關,我就先不實作程式碼了。
然後在tableView裡註冊這個cell:
newTableView.register(UITableViewCell.self, forCellReuseIdentifier: "adventureCell")
這麼一來table就可以使用這個cell了。
而swift同樣也提供了register(_:forHeaderFooterViewReuseIdentifier:)這個function供table註冊UINib或UITableViewHeaderFooterView供header/footer使用,實作的方法相同。
cell已經被table註冊了,接下來就是要決定cell的使用位置與時機。
這個需要使用dequeueReusableCell(withIdentifier:for:),搭配dataSource的tableView(_:cellForRowAt:)來對每一個indexPath的row做指定。
其實我們在class採用dataSource時就已經實作過dequeueReusableCell(withIdentifier:for:),這個function就是在table裡使用會存入佇列的可重複使用的cell,並使用identidier指定cell的形式。
那我們現在實作這個function。首先建立一筆資料:
var adventureCharacters = ["Finn", "Jack", "Beemo", "Princess Bubblegum", "Marceline", "Ice King"]
接下來定義dataSource的tableView(_:cellForRowAt:),並且定義cell採用我們剛剛設計的adventureCell形式,並將剛剛建立的資料依據列數指定給cell,第0列就取用陣列的第0筆資料,依此類推:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "adventureCell", for: indexPath)
cell.imageView?.image = UIImage(named: adventureCharacters[indexPath.row])
cell.textLabel?.text = adventureCharacters[indexPath.row]
return cell
}
如此一來表格就可以呈現我們想要的形式。
同樣之前實作過的,也可以對不同的section與不同的row指定不同的cell形式:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
switch indexPath.section {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath)
return cell
default:
switch indexPath.row {
case 0:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath)
return cell
case 1:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell3", for: indexPath)
return cell
default:
let cell = tableView.dequeueReusableCell(withIdentifier: "cell4", for: indexPath)
return cell
}
}
}
那我今天偷懶的講解就在這裡告一個段落,好累啊~~
下一回又是重頭戲UITableViewDelegate。
我一天之內能不能看完寫出文章啊......