# Binding TableView

## เริ่มจาก DataSource

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

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

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

![Xcode จะบอกว่ายังไม่สร้าง 2 function นะ](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LfJNg1nKXu7KjhFR4M4%2F-LfJNjVm41uZKu9d4ZhJ%2F6.gif?alt=media\&token=fba218a8-96a2-4464-b68f-b66bad3163ca)

โค้ดของเราจะเป็นแบบนี้ ให้เราตอบไปก่อนว่ามี 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
    }
}
```
{% 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 %}

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

![](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LfJNg1nKXu7KjhFR4M4%2F-LfJOX26NrcZLENfA2_3%2FScreen%20Shot%202019-05-20%20at%2015.40.11.png?alt=media\&token=6ec384a7-55b9-43a1-8db0-2f0347923970)

**อ้าว ไม่มีอะไรเกิดขึ้น อ๋อ สงสัยยังไม่ได้สร้าง 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](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LfJNg1nKXu7KjhFR4M4%2F-LfJQ01vtutc2s7f97q-%2F7.gif?alt=media\&token=22baf512-9ac8-48ea-a79a-fa8fc97631aa)

## ผูก DataSource ด้วย

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

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

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

![ผูกใน Document Outline](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LGpEjffgPCzsZHICtdY%2F-LGpEmb5-SPBb50ykyH6%2FlinkDataSource.gif?alt=media\&token=5a3bdf19-173d-49a0-961a-2a5826355f4c)

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

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

![ผูกผ่าน Connections Inspector](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LfJNg1nKXu7KjhFR4M4%2F-LfJQdoTb7q_RCjYsj27%2F8.gif?alt=media\&token=a48393f7-0869-46f3-8e7f-4e73a1a5dd8c)

ถ้ารันดูก็ยังว่างเปล่าไม่มีอะไรใน 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

![](https://144845262-files.gitbook.io/~/files/v0/b/gitbook-legacy-files/o/assets%2F-LGk7Utff0rVWsqK4eYO%2F-LfJNg1nKXu7KjhFR4M4%2F-LfJR-bshnZi9d_M2vJT%2FScreen%20Shot%202019-05-20%20at%2015.51.01.png?alt=media\&token=1a4b401e-c249-49e9-8215-3013f3502d15)

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

