【iOS/Swift/Beginner】JSONをDecodeしてTableViewに表示する

# ゴール
APIから取得したJSONの情報をTable Viewに表示する

![goal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/d90776a1-3492-5cd6-436a-fcaaf88533de.png)


# アジェンダ
1. 下準備
2. データをfetchする関数を作成
3. UITableViewControllerを作成
4. まとめ

# 1. 下準備
### 1.1. プロジェクトの作成
xcodeでプロジェクトを作成。Single View Appを選択する

### 1.2. Codableを使って雛形を作る
Newから新規swiftファイルを作成する
今回は以下のようにCup.swift作成

```swift:Cup.swift
import Foundation

struct Cup: Codable {
    var id: Int
    var name: String
    var description: String
    var price: Int
}
```

ViewController.swiftに以下を追記

```swift:ViewController.swift
var cups = [Cup]()
```


# 2. データをfetchする関数を作成
### 2.1. ViewController.swiftに以下の関数を追加する

```swift:ViewController.swift
    func fetchData() {
        let url = URL(string: "http://hereComesYourURL/cups")!
        
        URLSession.shared.dataTask(with: url) { data, response, error
            in
            guard let data = data else {
                print(error?.localizedDescription ?? "Unknown error")
                return
            }
            
            let decoder = JSONDecoder()
            
            if let cups = try? decoder.decode([Cup].self, from: data) {
                DispatchQueue.main.async {
                    self.cups = cups
                    self.tableView.reloadData()
                    print("Loaded \(cups.count) cups" )
                }
            } else {
                    print("Unable parse JSON response")
            }
        }.resume()
    }
```
### 2.2 作成したfetchData()をviewDidLoad()直下に宣言する

```swift:ViewController.swift
    override func viewDidLoad() {
        super.viewDidLoad()
        
        fetchData()   
    }
```

### 2.3. ここまでのまとめ
ViewController.swiftは以下のようになっているはず

```swift:ViewController.swift
import UIKit

class ViewController: UIViewController {
    var cups = [Cup]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        fetchData()   
    }
    
    func fetchData() {
        let url = URL(string: "http://hereComesYourURL/cups")!
        
        URLSession.shared.dataTask(with: url) { data, response, error
            in
            guard let data = data else {
                print(error?.localizedDescription ?? "Unknown error")
                return
            }
            
            let decoder = JSONDecoder()
            
            if let cups = try? decoder.decode([Cup].self, from: data) {
                DispatchQueue.main.async {
                    self.cups = cups
                    self.tableView.reloadData()
                    print("Loaded \(cups.count) cups" )
                }
            } else {
                    print("Unable parse JSON response")
            }
        }.resume()
    }
}
```
# 3. UITableViewControllerを作成
### 3.1. Storyboard編集
Main.storyboardへ移動
既存のViewControllerを選択して削除する
Library(com + shift + L)からTable View Controllerを選択してdrug and drop
![librray.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/fad62dfa-1b40-240a-2fde-85c501ad5e3c.png)

Storyboard右下の以下のアイコンをクリックしてEmbed In > Navigation Controllerを選択
![embedin.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/20adae75-ca3c-1517-4df6-984670105505.png)

Table View Cellを選択
![tableviewcell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/736b9c8e-dd58-6a69-633f-dc8cf2854bf3.png)


Attributes Inspectorでcellにidentifierを設定する。ここでは仮に"Cell"とする
![cell.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/37ece297-4c8e-6995-5429-65ba8acc7aa9.png)

Identity InspectorでViewControllerを選択する
![viewcontroller.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/8a2a3a56-5223-d9f6-33b7-32c61c68243b.png)


### 3.2. ViewController.swiftの編集
ViewController.swiftに戻る。UIViewControllerをUITableViewControllerに書き換える

```swift:ViewController.swift
class ViewController: UITableViewController {
```

override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Intを追記する

```swift:ViewController.swift
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cups.count
    }
```

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCellを追加する

```swift:ViewController.swift
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let cake = cups[indexPath.row]
        
        cell.textLabel?.text = "\(cup.name) = $\(cup.price)"
        cell.detailTextLabel?.text = cup.description
        
        return cell
    }
```

# まとめ
JSONを用意すれば以下のように表示できるはず
![goal.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/282045/d90776a1-3492-5cd6-436a-fcaaf88533de.png)

ViewController.swiftの全量は以下

```swift:ViewController.swift
import UIKit

class ViewController: UITableViewController {
    var cups = [Cup]()

    override func viewDidLoad() {
        super.viewDidLoad()
        
        fetchData()        
    }
    
    func fetchData() {
        let url = URL(string: "http://hereComesYourURL/cups")!
        
        URLSession.shared.dataTask(with: url) { data, response, error
            in
            guard let data = data else {
                print(error?.localizedDescription ?? "Unknown error")
                return
            }
            
            let decoder = JSONDecoder()
            
            if let cakes = try? decoder.decode([Cup].self, from: data) {
                DispatchQueue.main.async {
                    self.cups = cups
                    self.tableView.reloadData()
                    print("Loaded \(cups.count) cups" )
                }
            } else {
                    print("Unable parse JSON response")
            }
        }.resume()
    }
    
    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return cups.count
    }
    
    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Cell", for: indexPath)
        let cup = cups[indexPath.row]
        
        cell.textLabel?.text = "\(cup.name) = $\(cup.price)"
        cell.detailTextLabel?.text = cup.description
        
        return cell 
    }
}
```