เริ่มจาก DataSource
อย่างแรกเราเริ่มจากบอกว่าเราเป็น UITableViewDataSource ก่อน เพื่อให้ TableView ที่เราลากใส่ใน Main.storyboard สามารถดึงข้อมูลจาก controller นี้มาแสดง ซึ่งหลังจากพิมพ์ UITableViewDataSource เสร็จ Xcode จะบอกว่าเรายังไม่ได้ทำฟังก์ชั่น 2 อันนะ ก็ให้เราเพิ่มเข้าไป
อันแรก tableView(_:numberOfRowsInSection:) เป็นช่องทางให้ tableView ถามว่าจะมีกี่รายการ
อันที่สอง tableView(_:cellForRowAt:) ใช้ให้ TableView ขอว่าแต่ละรายการหน้าตาเป็นอย่างไร
โค้ดของเราจะเป็นแบบนี้ ให้เราตอบไปก่อนว่ามี 0 รายการ แต่ละอันให้เป็น cell เปล่า ๆ ไปก่อน
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return 0
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
override func viewDidLoad() {
super.viewDidLoad()
}
}
ใส่ Todo เข้ามา
จากนั้นให้เราสร้าง Todo ขึ้นมาแล้วให้ tableView(_:numberOfRowsInSection:) ตอบเป็นจำนวน items ใน todo ด้วย todo.totalItems ที่เราเตรียมไว้
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var todo = Todo()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todo.totalItems
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
override func viewDidLoad() {
super.viewDidLoad()
todo.add(item: TodoItem(title: "Buy milk", isDone: false))
todo.add(item: TodoItem(title: "Learning Swift", isDone: false))
}
}
บรรทัดที่ 5 สร้าง todo ขึ้นมาเก็บไว้ตั้งแต่ viewController นี้ถูกสร้างขึ้นมา
บรรทัดที่ 8 ตอบเป็นจำนวน items ใน todo ด้วย todo.totalItems ที่เราเตรียมไว้
บรรทัดที่ 17 - 18 ลองเพิ่ม todoItem เข้าไปก่อน
Refactor หน่อย ขี้เกียจพิมพ์
จะเห็นว่าเวลาเราสร้าง TodoItem เราจะต้องมาใส่ isDone เป็น false ตลอด เราน่าจะให้มันใส่ false เป็น default เลยได้ไหมถ้าไม่ระบุ
ให้เราแก้โค้ด เพิ่ม = false ใน init
import Foundation
class TodoItem {
var title: String
var isDone: Bool
init(title: String, isDone: Bool = false) {
self.title = title
self.isDone = isDone
}
}
แค่นี้เราก็จะเรียกได้แบบนี้
TodoItem(title: "Buy milk")
TodoItem(title: "Learning Swift", isDone: true)
แล้วเราจะได้ ViewController ของเราเป็นแบบนี้
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var todo = Todo()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todo.totalItems
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return UITableViewCell()
}
override func viewDidLoad() {
super.viewDidLoad()
todo.add(item: TodoItem(title: "Buy milk"))
todo.add(item: TodoItem(title: "Learning Swift"))
}
}
เมื่อเรารันจะได้แบบนี้
อ้าว ไม่มีอะไรเกิดขึ้น อ๋อ สงสัยยังไม่ได้สร้าง cell ใน storyboard
มาสร้าง TableViewCell กัน
กลับมาที่ Main.storyboard กันเหมือนเดิม
คลิ๊กเลือก TableView ของเรา
ไปที่ Attributes Inspector เพิ่ม Prototype cells เป็น 1
TableView จะมี TableViewCell โผล่ขึ้นมา
ให้เลือกที่ TableViewCell แล้ว เปิด Attributes Inspector เลือก Style เป็น Basic ใส่ Identifier เป็น todoItemCell
ผูก DataSource ด้วย
เราต้องบอก TableView ใน storyboard ด้วยว่า ViewController เป็น dataSource นะ เพราะว่า ViewController แค่บอกว่าฉันเป็น dataSource ได้นะ แต่ไม่มีอะไรบอกว่า เป็นของใคร TableView ไหน
วิธีผูก dataSource แบบแรกใน document outline
กด ctrl แล้วคลิ๊กลากจาก tableView ไปหา ViewController
วิธีผูกผ่าน Connections Inspector
ให้เลือก TableView เสร็จแล้วเปิด Connections Inspector
ลาก dataSource มาที่ ไอคอนสีเหลืองของ ViewController
ถ้ารันดูก็ยังว่างเปล่าไม่มีอะไรใน TableView
คืน TableViewCell ที่เราสร้าง
ใน tableView(_:cellForRowAt:) ยังคืนเป็น Cell เปล่า ๆ อยู่ ให้เราแก้เป็น
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "todoItemCell", for: indexPath)
}
Identifier ที่เราตั้งให้ TableViewCell ใน storyboard จะต้องตรงกันกับโค้ดตอนที่เรา dequeueReusableCell ไม่เช่นนั้น แอพจะ Crash เวลารัน
โค้ดสุดท้ายจะเป็นแบบนี้
import UIKit
class ViewController: UIViewController, UITableViewDataSource {
var todo = Todo()
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return todo.totalItems
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return tableView.dequeueReusableCell(withIdentifier: "todoItemCell", for: indexPath)
}
override func viewDidLoad() {
super.viewDidLoad()
todo.add(item: TodoItem(title: "Buy milk"))
todo.add(item: TodoItem(title: "Learning Swift"))
}
}
พอรันแล้วเราจะได้ Title มาสองอัน ทำไมหล่ะ ไม่เป็น Buy milk กับ Learning Swift
เพราะเรายังไม่ได้ผูก Title ใน todoItems กับ Cell เลย