Binding TableView

เอา TableView ที่เราสร้างมาเชื่อมกับ ViewController กันดีกว่า

เริ่มจาก DataSource

อย่างแรกเราเริ่มจากบอกว่า ViewController ของเราเป็น UITableViewDataSource ก่อน เพื่อให้ TableView ที่เราลากใส่ใน Main.storyboard สามารถดึงข้อมูลจาก controller นี้มาแสดง ซึ่งหลังจากพิมพ์ UITableViewDataSource เสร็จ Xcode จะ Error

ให้เรากดปุ่ม Fix แล้ว Xcode จะสร้างฟังก์ชั่น 2 อันเพิ่มมาให้เรา

อันแรก tableView(_:numberOfRowsInSection:) เป็นช่องทางให้ tableView ถามว่าจะมีกี่รายการ

อันที่สอง tableView(_:cellForRowAt:) ใช้ให้ TableView ขอว่าแต่ละรายการหน้าตาเป็นอย่างไร

โค้ดของเราจะเป็นแบบนี้ ให้เราตอบไปก่อนว่ามี 0 รายการ แต่ละอันให้เป็น cell เปล่า ๆ ไปก่อน

ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        0
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        UITableViewCell()
    }

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
    }
}

ใส่ Todo เข้ามา

จากนั้นให้เราสร้าง Todo ขึ้นมาแล้วให้ tableView(_:numberOfRowsInSection:) ตอบเป็นจำนวน items ใน todo ด้วย todo.totalItems ที่เราเตรียมไว้

ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    var todo = Todo()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        todo.totalItems
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        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

TodoItem.swift
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 ของเราเป็นแบบนี้

ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    var todo = Todo()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        todo.totalItems
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        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 กันเหมือนเดิม

  1. คลิ๊กเลือก TableView ของเรา

  2. ไปที่ Attributes Inspector เพิ่ม Prototype cells เป็น 1

  3. TableView จะมี TableViewCell โผล่ขึ้นมา

  4. ให้เลือกที่ TableViewCell แล้ว เปิด Attributes Inspector เลือก Style เป็น Basic ใส่ Identifier เป็น todoItemCell

ผูก DataSource ด้วย

เราต้องบอก TableView ใน storyboard ด้วยว่า ViewController เป็น dataSource นะ เพราะว่า ViewController แค่บอกว่าฉันเป็น dataSource ได้นะ แต่ไม่มีอะไรบอกว่า เป็นของใคร TableView ไหน

วิธีผูก dataSource แบบแรกใน document outline

  1. กด ctrl ค้างไว้แล้วคลิ๊กลากจาก tableView ไปหา ViewController

  2. เลือก dataSource

วิธีผูกผ่าน Connections Inspector

  1. ให้เลือก TableView เสร็จแล้วเปิด Connections Inspector

  2. ลาก dataSource มาที่ ไอคอนสีเหลืองของ ViewController

ถ้ารันดูก็ยังว่างเปล่าไม่มีอะไรใน TableView

คืน TableViewCell ที่เราสร้าง

ใน tableView(_:cellForRowAt:) ยังคืนเป็น Cell เปล่า ๆ อยู่ ให้เราแก้เป็น

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    tableView.dequeueReusableCell(withIdentifier: "todoItemCell", for: indexPath)
}

Identifier ที่เราตั้งให้ TableViewCell ใน storyboard จะต้องตรงกันกับโค้ดตอนที่เรา dequeueReusableCell ไม่เช่นนั้น แอปจะ Crash เวลารัน

โค้ดสุดท้ายจะเป็นแบบนี้

ViewController.swift
import UIKit

class ViewController: UIViewController, UITableViewDataSource {

    var todo = Todo()

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        todo.totalItems
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        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 เลย

Last updated