> For the complete documentation index, see [llms.txt](https://pakornpat.gitbook.io/ios-app/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://pakornpat.gitbook.io/ios-app/v1/binding-tableview.md).

# Binding TableView

## เริ่มจาก DataSource

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

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

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

![Xcode จะบอกว่ายังไม่สร้าง 2 function นะ](/files/-LGp8BRV9a6MJsc4wh6Y)

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

{% code title="ViewController.swift" %}

```swift
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()
    }
}
```

{% endcode %}

## ใส่ Todo เข้ามา

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

{% code title="ViewController.swift" %}

```swift
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))
    }
}
```

{% endcode %}

**บรรทัดที่ 5** สร้าง todo ขึ้นมาเก็บไว้ตั้งแต่ viewController นี้ถูกสร้างขึ้นมา\
**บรรทัดที่ 8** ตอบเป็นจำนวน items ใน todo ด้วย **todo.totalItems** ที่เราเตรียมไว้\
**บรรทัดที่ 17 - 18** ลองเพิ่ม todoItem เข้าไปก่อน

## Refactor หน่อย ขี้เกียจพิมพ์

จะเห็นว่าเวลาเราสร้าง TodoItem เราจะต้องมาใส่ isDone เป็น false ตลอด เราน่าจะให้มันใส่ false เป็น default เลยได้ไหมถ้าไม่ระบุ

ให้เราแก้โค้ด เพิ่ม **= false** ใน init

{% code title="TodoItem.swift" %}

```swift
import Foundation

class TodoItem {
    var title: String
    var isDone: Bool

    init(title: String, isDone: Bool = false) {
        self.title = title
        self.isDone = isDone
    }

    func toggleIsDone() {
        self.isDone = !self.isDone
    }
}
```

{% endcode %}

แค่นี้เราก็จะเรียกได้แบบนี้

```swift
TodoItem(title: "Buy milk")
TodoItem(title: "Learning Swift", isDone: true)
```

แล้วเราจะได้ ViewController ของเราเป็นแบบนี้

{% code title="ViewController.swift" %}

```swift
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"))
    }
}
```

{% endcode %}

เมื่อเรารันจะได้แบบนี้

![](/files/-LGp9g9xERs6afUbtZIL)

**อ้าว ไม่มีอะไรเกิดขึ้น อ๋อ สงสัยยังไม่ได้สร้าง cell ใน storyboard**

## มาสร้าง TableViewCell กัน

กลับมาที่ Main.storyboard กันเหมือนเดิม&#x20;

1. คลิ๊กเลือก TableView ของเรา
2. ไปที่ Attributes Inspector เพิ่ม **Prototype cells** เป็น 1
3. TableView จะมี TableViewCell โผล่ขึ้นมา
4. ให้เลือกที่ TableViewCell แล้ว เปิด Attributes Inspector เลือก **Style เป็น Basic** ใส่ Identifier เป็น **todoItemCell**

![สร้าง Prototype cell แบบ Basic](/files/-LGpDy68ma5iqCuXI5mI)

## ผูก DataSource ด้วย

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

**วิธีผูก dataSource แบบแรกใน document outline**&#x20;

1. กด ctrl แล้วคลิ๊กลากจาก tableView ไปหา ViewController&#x20;
2. เลือก dataSource

![ผูกใน Document Outline](/files/-LGpEmb5-SPBb50ykyH6)

**วิธีผูกผ่าน Connections Inspector**&#x20;

1. ให้เลือก TableView เสร็จแล้วเปิด Connections Inspector
2. ลาก dataSource มาที่ ไอคอนสีเหลืองของ ViewController&#x20;

![ผูกผ่าน Connections Inspector](/files/-LHSYH4XYelSV7S2l69C)

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

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

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

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

{% hint style="danger" %}
Identifier ที่เราตั้งให้ TableViewCell ใน storyboard จะต้องตรงกันกับโค้ดตอนที่เรา dequeueReusableCell ไม่เช่นนั้น แอพจะ Crash เวลารัน
{% endhint %}

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

{% code title="ViewController.swift" %}

```swift
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"))
    }
}
```

{% endcode %}

พอรันแล้วเราจะได้ Title มาสองอัน ทำไมหล่ะ ไม่เป็น Buy milk กับ Learning Swift

![](/files/-LGpGAOM-nHvUh4OyogL)

เพราะเรายังไม่ได้ผูก Title ใน todoItems กับ Cell เลย
