Swiftで簡単なTODOアプリを作ってみよう

![スクリーンショット 2018-03-29 18.46.17.png](https://qiita-image-store.s3.amazonaws.com/0/63060/cf01692b-c314-725a-2e44-47ae8ec11f5b.png)

# ■まえがき
## 書いてあること
- xcodeにて、TableViewを使用した2ページのアプリの作成

## モチベーション
- 練習のためにTODOアプリを作ってみようとした。
- 多くの記事が古いswiftのバージョンが前提になっており、超つまずいた。
- 特に、swift3.0のアップデートにより、コードの記述ルールが変更になった影響が大きい。

参照：Swift 3.0の変更点まとめ
https://dev.classmethod.jp/smartphone/iphone/implemented_proposals_for_swift3/

# ■解説
## 流れ
STEP1：プロジェクトの立ち上げ

STEP2：メインストーリーボードの設定

- 画面サイズの設定(iPhoneSEにサイズ変更)
- 新規ViewControllerの追加
- パーツの配置
  - ナビゲーションバーを両画面に追加
  - バーボタンアイテムの追加
  - テキストフィールドの追加
  - ボタンの追加
  - テーブルビューの追加
  - テーブルビューセルの追加
- テーブルビューセルに名前をつける
- テーブルビューにViewControllerを紐付け
  - DataSource
  - Delegate
- 画面遷移の設定
- 新規swiftファイルの追加と紐付け
  - AddController.swiftの追加
  - ViewControllerと紐付け

STEP3：AddController.swiftの編集

- 変数の設置（Stringの配列）
- テキストフィールドの設定
  - テキストフィールドの紐付け
- 追加ボタンの設定
  - 追加ボタンの紐付け
  - 追加ボタンの実装
      - 変数に入力内容を入れる
      - 追加ボタン押したらフィールドを空にする
      - 変数の中身をUDに追加

STEP4：ViewControllerの編集

- classの継承を追加
  - UITableViewDelegateの追加
  - UITableViewDataSourceの追加
- UITableView、numberOfRowsInSectionの追加(表示するcell数を決める)
  - 枠を作る
  - 戻り値の設定(表示するcell数)
- UITableView、cellForRowAtの追加(表示するcellの中身を決める)
  - 枠を作る
  - 変数を作る
  - 変数の中身を作る
  - 戻り値の設定（表示する中身)
- 追加画面で入力した内容を取得する
  - データの存在確認
  - データを渡す

STEP5：起動してみる

## ■STEP1：プロジェクトを立ち上げる
- シングルビューを選択

![スクリーンショット 2018-03-14 10.58.39.png](https://qiita-image-store.s3.amazonaws.com/0/63060/352c11cc-6005-e955-971f-295dc28482aa.png)

- プロジェクト名などを入力

![スクリーンショット 2018-03-14 11.02.20.png](https://qiita-image-store.s3.amazonaws.com/0/63060/d7333132-b220-8039-fabb-eba46521a2c5.png)

- 今回は「MyTODO」にしました

![スクリーンショット 2018-03-29 12.41.30.png](https://qiita-image-store.s3.amazonaws.com/0/63060/84352c64-22e7-a570-2088-4457fc0a9ffb.png)


さらに詳しくはこちらの記事がわかりやすいです
https://type.jp/et/feature/3008

## ■STEP2：メインストーリーボードの設定
### 画面サイズの設定(iPhoneSEにサイズ変更)
- 作成するアプリの画面サイズを設定しましょう
- 今回はSEを選択しました（macAirを使っているとiPhone8などではシミュレーターがはみ出てしまうため）

![スクリーンショット 2018-03-14 11.04.40.png](https://qiita-image-store.s3.amazonaws.com/0/63060/7cd8abc4-c3bd-1839-93ae-aa94148b4d6a.png)


### 新規ViewControllerの追加
- パーツからViewControllerを選んでドラッグ&ドロップ

![スクリーンショット 2018-03-29 13.59.22.png](https://qiita-image-store.s3.amazonaws.com/0/63060/bb72041b-c3eb-ecd0-0124-240ba7756efe.png)

### パーツの配置
#### ナビゲーションバーを両画面に追加
- パーツからNavigationBarを選んでドラッグ&ドロップ

![スクリーンショット 2018-03-29 15.21.01.png](https://qiita-image-store.s3.amazonaws.com/0/63060/cb758873-b553-9e67-01ca-6ce9856b05f4.png)

- ついでにタイトルも変更しましょう。システムに影響しないので、なんでもokです
![スクリーンショット 2018-03-29 15.21.46.png](https://qiita-image-store.s3.amazonaws.com/0/63060/b0cc2c0e-2048-8392-1208-b9ab7ebb1fa0.png)


#### バーボタンアイテムの追加
- パーツからBarButtonItemを選んでドラッグ&ドロップ

![スクリーンショット 2018-03-29 15.26.42.png](https://qiita-image-store.s3.amazonaws.com/0/63060/fed81052-bf6f-020e-713f-9aa901a176d3.png)

- アトリビュートメニューから、Styleを「DONE」にしましょう
    - plainとborderは最新のiosでサポートされていないようです
- タイトルも変更しておきましょう。システムに影響しないので、なんでもokです

![スクリーンショット 2018-03-29 15.26.52.png](https://qiita-image-store.s3.amazonaws.com/0/63060/dfc53d95-ec4c-80d1-711b-5c5c01e926be.png)


#### テキストフィールドの追加
- パーツからTextFieldを選んでドラッグ&ドロップ

![スクリーンショット 2018-03-29 15.32.35.png](https://qiita-image-store.s3.amazonaws.com/0/63060/c3626a10-61df-a6da-0de3-5655d506694a.png)


#### ボタンの追加
- パーツからButtonを選んでドラッグ&ドロップ
- ついでにタイトルも変更しておきましょう。システムに影響しないので、なんでもokです

![スクリーンショット 2018-03-29 15.32.57.png](https://qiita-image-store.s3.amazonaws.com/0/63060/aa4f3a99-ace4-8c20-0744-35b4431b6cf5.png)


#### テーブルビューの追加
- UIパーツの中からTableViewを選んでドラッグ&ドロップ
- このままだと綺麗に表示されないので、画面いっぱいに広げましょう

![スクリーンショット 2018-03-29 15.36.21.png](https://qiita-image-store.s3.amazonaws.com/0/63060/1b547340-d7cb-5b77-f8ae-392ebf0fe086.png)


#### テーブルビューセルの追加
- パーツからTableViewCellを選んでドラッグ&ドロップ
- ＊テーブルビューに重なるように！

![スクリーンショット 2018-03-29 15.36.38.png](https://qiita-image-store.s3.amazonaws.com/0/63060/2b624d0c-953a-3b72-1469-fb155ee8dc06.png)


### テーブルビューセルに名前をつける
- アトリビュートからidentifierを設定する
- ＊なんでもok。ここでは **「TodoCell」** とする

![スクリーンショット 2018-03-29 15.37.12.png](https://qiita-image-store.s3.amazonaws.com/0/63060/ad742610-2e10-e9ea-c642-8e052cfc0ef4.png)


### テーブルビューにViewControllerを紐付け
- TableViewを選択
- 右のメニューから「Connection Inspector」を選択
- OutletsのdataSourceとdelegateからミョン！とドラッグしてください

![スクリーンショット 2018-04-12 12.36.52.png](https://qiita-image-store.s3.amazonaws.com/0/63060/ac3e1b17-f6b7-66f9-1445-09f503ce2198.png)

![スクリーンショット 2018-04-12 12.37.05.png](https://qiita-image-store.s3.amazonaws.com/0/63060/32f8bf41-37ee-7007-ea35-967b7aac2300.png)



### 画面遷移の設定
- 追加ボタンを選択してcontrolを押しながら追加画面にドラッグ＆ドロップ

![スクリーンショット 2018-03-29 15.43.52.png](https://qiita-image-store.s3.amazonaws.com/0/63060/8b6c90f9-510b-141b-456c-1e2dc1c36aff.png)


- メニューから「show」を選択する

![スクリーンショット 2018-03-29 15.44.22.png](https://qiita-image-store.s3.amazonaws.com/0/63060/79d4dd7c-b2b0-c951-e4d2-10f4b4c565bc.png)


- 戻るボタンも同様に操作して、下記のようになればok

![スクリーンショット 2018-03-29 15.46.21.png](https://qiita-image-store.s3.amazonaws.com/0/63060/e746d688-1053-896f-44ac-82ff94635e5e.png)



### 新規swiftファイルの追加と紐付け
#### AddController.swiftの追加
- File>New>Fileを選択する

![スクリーンショット 2018-03-29 15.47.58.png](https://qiita-image-store.s3.amazonaws.com/0/63060/0f4e8425-59d0-a888-d807-4248a355d2c8.png)


- CocoaTouchClassを選択してNext

![スクリーンショット 2018-03-29 15.48.03.png](https://qiita-image-store.s3.amazonaws.com/0/63060/0a37cb0b-905a-f31b-157b-7aad7757b232.png)


- Class名を入力する
  - ＊なんでもok。ここでは **「AddController」** とする。
  - Subclass of以下はそのままでok
- 保存する
  - 場所は「MyTODO」フォルダの直下でok（ViewController.swiftと同じ階層）

![スクリーンショット 2018-03-29 15.48.13.png](https://qiita-image-store.s3.amazonaws.com/0/63060/7d22ecdd-bf8f-924f-a415-00a297a2a0df.png)


#### ViewControllerと紐付け
- 追加したAddController.swiftとTODO追加画面の紐付けをします
- 要は、この画面の制御にはこのswiftファイルを使用しますよということです
- 下記の場所のから作成したAddControllerを選択すればokです

![スクリーンショット 2018-03-29 15.49.56.png](https://qiita-image-store.s3.amazonaws.com/0/63060/bff9175d-9e18-9e5a-14da-b12b6aeca35a.png)


## ■STEP3：AddControllerの編集
- 先に完成形を確認

```swift:AddController.swift
//  AddController.swift
import UIKit

//変数の設置
var TodoKobetsunonakami = [String]()

class AddController: UIViewController {

    //テキストフィールドの設定
    @IBOutlet weak var TodoTextField: UITextField!

    //追加ボタンの設定
    @IBAction func TodoAddButten(_ sender: Any) {
        //変数に入力内容を入れる
        TodoKobetsunonakami.append(TodoTextField.text!)
        //追加ボタンを押したらフィールドを空にする
        TodoTextField.text = ""
        //変数の中身をUDに追加
        UserDefaults.standard.set( TodoKobetsunonakami, forKey: "TodoList" )
    }

    //最初からあるコード
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    //最初からあるコード
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }    
}
```

### 変数の設置
- TODOの内容を保存するための変数を作ります
- 複数の値を扱うので、配列型にします
- class（ファイル）を跨って使用するため、classの前（import UIKit直下）に記載します
- 変数名はなんでもok
- わかりやすく **「TodoKobetsunonakami(TODO個別の中身)」** としておきます

```swift:AddController.swift
import UIKit
var TodoKobetsunonakami = [String]()
```

### テキストフィールドの設定
- TODOの内容を入力するためのテキストフィールドを設定します
- ストーリーボードからコードにドラッグ＆ドロップ
- 位置はclass名のすぐ下におきましょう

![スクリーンショット 2018-03-29 15.55.26.png](https://qiita-image-store.s3.amazonaws.com/0/63060/a5ab90c1-045d-b3fe-2bfd-f247c7fa3daa.png)


- 下記の設定になっているかを確認
  - Connection:Outlet
  - Name:何でもok（ここでは **「TodoTextField」** ）
  - Type:UITextField
- okであればconnectを押す

![スクリーンショット 2018-03-29 15.55.48.png](https://qiita-image-store.s3.amazonaws.com/0/63060/928c4402-c19e-0623-e102-8ff5904dae20.png)


### 追加ボタンの設定
#### 追加ボタンの紐付け
- テキストを入力した後に押す「追加する」ボタンの制御を行います
- 先ほどのように、パーツをコードに紐付けましょう
- 位置はclass名のすぐ下におきましょう

![スクリーンショット 2018-03-29 15.56.43.png](https://qiita-image-store.s3.amazonaws.com/0/63060/7361bdf6-dbd6-5591-60ff-421c7e53dc97.png)


- 下記の設定になっているかを確認
  - Connection:Action
  - Name:何でもok（ここでは **「TodoAddButton」** ）
  - Type:Any
  - Event:ToucUpInside
  - Argument:Sender
- okであればconnectを押す

![スクリーンショット 2018-03-29 15.56.58.png](https://qiita-image-store.s3.amazonaws.com/0/63060/2885e65a-c208-c959-c179-64b09b2aa5f1.png)


- テキストフィールドとボタンを紐付けるとこんな感じになります

```swift:AddController.swift
@IBOutlet weak var TodoTextField : UITextField!
@IBAction func TodoAddButton(_ sender: Any) {
    }
```

#### 変数に入力内容を入れる
- 先ほど作成した変数（TodoKobetsunonakami）にテキストフィールドに入力した内容を入力する命令を書く
- 位置はTodoAddButtonの{}の中です

```swift:AddController.swift
TodoKobetsunonakami.append(TodoTextField.text!)
```

#### 追加ボタンを押したらフィールドを空にする
- 追加ボタンを押した時にテキストフィールドの中身を空にする命令を書く

```swift:AddController.swift
TodoTextField.text = ""
```

#### 変数の中身をUDに追加
- 変数の中身をUserDefaultsに保存する命令を書く
- UserDefaultsとはデータベースを作るほどのものではないデータを簡単に保存しておける箱のようなもの
- データを保存しておく場所の名前をつけましょう
- 名前は何でもok（ここでは **「TodoList」** ）

```swift:AddController.swift
UserDefaults.standard.set( TodoKobetsunonakami, forKey: "TodoList" )
```


## ■STEP4：ViewControllerの編集
- 先に完成形を確認

```swift:ViewController.swift
//  ViewController.swift
import UIKit

//classの継承を追加
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource {

    //UITableView、numberOfRowsInSectionの追加(表示するcell数を決める)
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //戻り値の設定(表示するcell数)
        return TodoKobetsunonakami.count
    }

    //UITableView、cellForRowAtの追加(表示するcellの中身を決める)
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        //変数を作る
        let TodoCell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "TodoCell", for: indexPath)
        //変数の中身を作る
        TodoCell.textLabel!.text = TodoKobetsunonakami[indexPath.row]
        //戻り値の設定（表示する中身)
        return TodoCell
    }


    //最初からあるコード
    override func viewDidLoad() {
        super.viewDidLoad()
        //追加画面で入力した内容を取得する
        if UserDefaults.standard.object(forKey: "TodoList") != nil {
            TodoKobetsunonakami = UserDefaults.standard.object(forKey: "TodoList") as! [String]
        }
    }

    //最初からあるコード
    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
    }
}
```

### classの継承を追加
- TableViewを使うために、classを呼び出す
- classのUIViewControllerの後ろに、UITableViewDelegateとUITableViewDataSourceを追加する

```swift:ViewController.swift
class ViewController: UIViewController,UITableViewDelegate,UITableViewDataSource
```

### UITableView、numberOfRowsInSectionの追加(表示するcell数を決める)
#### 枠を作る
- classの宣言直下に下記の内容を追記
- xcodeのアナウンスから入力してもok
  - ＊継承を入力するとxcodeがfixを促してくるので、案内に従えば勝手に挿入される

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

#### 戻り値の設定(表示するcell数)
- returnの行を追記する

```swift:ViewController.swift
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    //戻り値の設定(表示するcell数)
    return TodoKobetsunonakami.count
}
```

### UITableView、cellForRowAtの追加(表示するcellの中身を決める)
#### 枠を作る
- numberOfRowsInSectionの直下に下記の内容を追記
- xcodeのアナウンスから入力してもok
- ＊継承を入力するとxcodeがfixを促してくるので、案内に従えば勝手に挿入される

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

#### 変数を作る
- TodoCellに表示するための変数を作る命令
- 下記のコードを追記する
- ポイントはindexPathの最初の文字が小文字になること

```swift:ViewController.swift
let TodoCell : UITableViewCell = tableView.dequeueReusableCell(withIdentifier: "TodoCell", for: indexPath)
```

#### 変数の中身を作る
- TodoCell変数に入力したTODOの中身を入れる命令
- 下記のコードを追記する

```swift:ViewController.swift
TodoCell.textLabel!.text = TodoKobetsunonakami[indexPath.row]
```

#### 戻り値の設定（表示する中身)
- 表示する中身としてどんな情報を渡すか決める命令
- 下記のコードを追記する

```swift:ViewController.swift
return TodoCell
```


### 追加画面で入力した内容を取得する
#### データの存在確認
- 画面を起動した時に、TodoList（入力したTODOのテキストが入っている場所）に何かしらのデータがあるかどうか確認する命令
- 下記のコードを追記する
- super.viewDidLoad()の直下に追記する

```swift:ViewController.swift
if UserDefaults.standard.object(forKey: "TodoList") != nil {}
```

#### データを渡す
- TodoListにデータがあった場合、TodoKobetsunonakami変数にデータを渡す命令

```swift:ViewController.swift
if UserDefaults.standard.object(forKey: "TodoList") != nil {
  TodoKobetsunonakami = UserDefaults.standard.object(forKey: "TodoList") as! [String]
}
```


## ■STEP5：起動してみる
- 実行して確認！
- お疲れ様でした！

![スクリーンショット 2018-03-29 18.46.17.png](https://qiita-image-store.s3.amazonaws.com/0/63060/cf01692b-c314-725a-2e44-47ae8ec11f5b.png)

# アプリが完成したら
## いいね！＆コメント欄にワッフルワッフル！と叫んでもらえると喜びます😄👍

# NextStage!

**🎉TODOアプリを作ってみようシリーズ**

📱SwiftでTableViewを使ってみよう
https://qiita.com/TD3P/items/cafa8e20029047993025

📱Swiftで簡単なTODOアプリを作ってみよう
https://qiita.com/TD3P/items/8f474358d1dd789557f3

📱Swiftでカスタムセルを再利用したTODOアプリを作ってみよう
https://qiita.com/TD3P/items/116a2199b1f872ac6471

📱SwiftでCoreDataを使ったTODOアプリを作ってみよう
https://qiita.com/TD3P/items/adbbeee827995cffd509

📱SwiftでRealmを使ったTODOアプリを作ってみよう
https://qiita.com/TD3P/items/616e0dbd364179ca284b

---

📱Flutterで基本のTODOアプリを作ってみよう
https://qiita.com/pe-ta/items/b3b7458059c1fd7efcf0

📱Flutterでページ遷移するTODOアプリを作ってみよう
https://qiita.com/pe-ta/items/e547c4cf460319f5093c

📱Flutter x Firestore で気軽に永続化してオラオラする方法
https://qiita.com/pe-ta/items/ccd49fc396b063a821af