# 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 เลย


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://pakornpat.gitbook.io/ios-app/v1/binding-tableview.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
