Swift × Realmでおしゃれなメモアプリを作ってみようの巻


# 概要
この記事は、Realmを使ったTODOメモアプリの作成記録です。

CRUDとは何か簡単に説明できる人向けになるので、全くの初心者の方は「CRUD」の意味を調べてから臨むようにしてください🚗


## 開発環境

|項目||
|---|---|
| PC | MacBook Air 2017 |
| IDE | Xcode Ver. 12.4|
|言語| Swift 5 |
|データベース| Realm |

#目次

1.主な流れ
2.いざ開発！！
3.コードの全容
4.Storyboard
5.終わりに




# 💫何するのー？

## ■やること
Realmを使った簡単なアプリ作成
ちなみにRealm=レルムです👍


## ■What We Learn
- Realmの基本的な実装を理解できる
- NCMBよりもう一段階データベースを深く学べる

## ■Realmを使うメリット
- 保存したデータをローカル環境で可視化できる（userDefaultsとの違い）
- 世界中で使われているので参考ドキュメントが豊富（英語中心だけど😂）



## ■主な流れ
- プロジェクトの作成
- cocoapodでrealmを追加
- ストーリーボードの設定
- モデルクラスの作成
- セルクラスの作成
- ViewControllerの実装
- 完成！


# 🛠本編

## ◼️プロジェクトの作成
- iOS→Appを選択
- 今回のプロダクトネームは「RealmTodo」にしました

![スクリーンショット 2021-06-12 10.20.10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/ed33c9df-f67e-e42a-f723-019628c47cb7.png)


## ◼️cocoaPodsでRealmを追加

＊cocoapodの導入方法はこちらを参照
https://qiita.com/pekocalypse/items/b80f6c343355a872dde6

### １：cocoapodを入れるのは超簡単下記のコマンドを入れるだけ

```
<!-- cocoapodsをインストール -->
$ sudo gem install cocoapods

<!-- バージョンを確認 -->
$ pod --version
10.0.0
```
注意：Cocoapodsは最新Versionの10.0以上にアップデートしてください！


### ２：先ほどのRealmTodoプロジェクトフォルダに移動して、CocoaPodsを初期化しPodFileを作成しましょう

```
$ cd ~/RealmTodo
$ pod init
```
すると、こんな感じで`Podfile`が作成されます
![スクリーンショット 2021-06-12 10.26.53.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/e4de7c9d-f0c5-aa07-2aab-f3690d33ad04.png)


### 3:作成された`Podfile`を編集しましょう
編集は、viで編集してもエディターで編集してもokです。

```ruby

<!-- 初期状態 -->

# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'

target 'RealmTodo' do
  # Comment the next line if you're not using Swift and don't want to use dynamic frameworks
  use_frameworks!

  # Pods for RealmTodo

end

<!-- 編集してこんな感じにしましょう -->

target 'RealmTodo' do
  use_frameworks!
  pod 'RealmSwift'
end

```

### 4:Realmをインストールします

```
$ pod install
Analyzing dependencies
Downloading dependencies
Installing Realm (10.7.6)
Installing RealmSwift (10.7.6)
Generating Pods project
Integrating client project
```
すると、プロジェクトフォルダにがこのように変化します

<img width="816" alt="スクリーンショット 2019-02-16 15.59.42.png" src="https://qiita-image-store.s3.amazonaws.com/0/63060/f2af238d-17a2-14f0-7ba5-5daaaf14238b.png">

### 5：xcodeでプロジェクトを開き直しましょう

realmを入れた後は、`RealmTodo.xcodeproj`ではなく、`RealmTodo.xcworkspace`からプロジェクトを開きましょう
<img width="206" alt="スクリーンショット 2019-02-16 16.03.13.png" src="https://qiita-image-store.s3.amazonaws.com/0/63060/8![スクリーンショット 2021-06-12 10.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/40b68e06-a8c9-412c-1eaf-af98fb904118.png)
![スクリーンショット 2021-06-12 10.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/cd0bc809-54df-9ba4-d688-2fe8281dfcc4.png)
![スクリーンショット 2021-06-12 10.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/b721be6c-d43f-fe76-0a11-6039c1b627f6.png)
![スクリーンショット 2021-06-12 10.33.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/42aa3746-5a1c-e84a-1eb3-7394da10226a.png)
cd3c9ef-252e-1f8b-13ed-9844861dad3c.png">


## ◼️モデルクラスの作成
やること：　Realmに保存したいデータの項目とデータ型を定義します

- まずはswiftファイル("subclass of"は"NSObjectを選択")を追加します
- 名前は`RealmData.swift` にしました
- ファイルを作成後、下記のように内容を編集します
- 今回は、TODOの項目名(todo)、メモ内容(memo)を文字列で保存します
- `import`が必要なので注意です！
- 記入直後は、xcodeから赤い警告が出ますが、一度buildすると消えますのでご安心ください

```RealmData.swift
import UIKit
import RealmSwift // 必須

class RealmData: Object { // ObjectはRealm固有のデータ型
    
    @objc dynamic var todo: String? = "" //データには必ず@objc dynamic varをつける
    @objc dynamic var memo: String? = ""
    
}
```



## ◼️AddViewController（メモ追加画面）の実装

```AddViewController.swift
import UIKit
import RealmSwift

class AddViewController: UIViewController {

    @IBOutlet var todoTextField: UITextField!
    @IBOutlet var memoTextView: UITextView!
    @IBOutlet var saveButton: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //ボタンを丸くする
        saveButton.layer.cornerRadius = saveButton.bounds.height/2
        saveButton.layer.masksToBounds = true
        
        // Realmの中身を確認するためのprint文
        print(Realm.Configuration.defaultConfiguration.fileURL!)
    }
    
    @IBAction func save(){
        
        // .realm拡張子のデータベースをローカルに作成
        let realm = try! Realm()
        
        // RealmDataクラスをインスタンス化（実体化）
        let realmData = RealmData()
        
        // インスタンス化したオブジェクトに値をセット
        realmData.todo = todoTextField.text!
        realmData.memo = memoTextView.text!
        
        // 保存のコード(データベースに書き込み)
        try! realm.write {
            realm.add(realmData)
        }
        
        navigationController?.popViewController(animated: true)
        
        // Realmの中身を確認するためのprint文
        print(Realm.Configuration.defaultConfiguration.fileURL!)
        
    } // これで保存（CRUDのC）はおしまい！
    
}

```

## ◼️ViewController（メモ表示画面）の実装

```ViewController.swift
import UIKit
import RealmSwift

class ViewController: UIViewController, UITableViewDelegate, UITableViewDataSource{
    
    @IBOutlet var todoTableView: UITableView!
    
    // RealmData型の変数を用意（まだ空っぽの配列）
    var todoList: Results<RealmData>!

    override func viewDidLoad() {
        super.viewDidLoad()
        
        // TableViewの教材参照
        self.todoTableView.delegate = self
        self.todoTableView.dataSource = self
    }
    
    override func viewWillAppear(_ animated: Bool) {
        
        // Realm使う宣言！
        let realm = try! Realm()
        
        // Realmから受け取るデータをtodoList変数（配列）に突っ込む
        self.todoList = realm.objects(RealmData.self)
        
        // tableViewを更新
        todoTableView.reloadData()
        
        // Realmの中身を確認するためのprint文
        print(Realm.Configuration.defaultConfiguration.fileURL!)
    }
    
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        
        // todoList変数（配列）に格納されてるデータ
        return todoList.count
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        
        // TableViewの教材参照
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath)
        
        // 取得したTodoリストのindexPath.row番目をeachData変数に代入
        let eachData = todoList[indexPath.row]
        
        // セルに反映
        cell.textLabel?.text = eachData.todo
            
        return cell
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        
        // 画面遷移先を指定
        performSegue(withIdentifier: "toEditVC", sender: nil)
        
        tableView.deselectRow(at: indexPath, animated: true)
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toEditVC" {
            
            let indexPath = todoTableView.indexPathForSelectedRow!
            
            let destination = segue.destination as? EditViewController
            
            destination?.passedNumber = indexPath.row
        }
    }
    
   
}
```

## ◼️EditViewController（メモ編集・削除画面）の実装

```EditViewController.swift
import UIKit
import RealmSwift

class EditViewController: UIViewController {
    
    // ViewControllerから渡されたindexPath.row
    var passedNumber = 0
    
    // RealmData型の変数を用意（まだ空っぽの配列）
    var todoList: Results<RealmData>!
    
    @IBOutlet var editTextField: UITextField!
    @IBOutlet var editTextView: UITextView!
    @IBOutlet var updateButton: UIButton!

    override func viewDidLoad() {
        super.viewDidLoad()

        // ボタンを丸くする
        updateButton.layer.cornerRadius = updateButton.bounds.height/2
        updateButton.layer.masksToBounds = true
    }
    
    override func viewWillAppear(_ animated: Bool) {
        
        // Realm使う宣言！
        let realm = try! Realm()
        
        // Realmから受け取るデータをtodoList変数（配列）に突っ込む
        self.todoList = realm.objects(RealmData.self)
        
        // 取得したTodoリストのPassedNumber番目をeditData変数に代入
        let editData = todoList[passedNumber]
        
        // TextFieldとTextViewに値をだいにゅ〜
        editTextField.text = editData.todo
        editTextView.text = editData.memo
        
        // Realmの中身を確認するためのprint文
        print(Realm.Configuration.defaultConfiguration.fileURL!)
        
    }
    
    
    @IBAction func update(){
        
        // Realm使う宣言！
        let realm = try! Realm()
        
        // 更新のコード(データベースに上書き)
        try! realm.write {
            self.todoList[passedNumber].todo = editTextField.text!
            self.todoList[passedNumber].memo = editTextView.text!
        }
        
        navigationController?.popViewController(animated: true)
        
        // Realmの中身を確認するためのprint文
        print(Realm.Configuration.defaultConfiguration.fileURL!)
    
    } //更新(CRUDのU)終わり！
    
    
    @IBAction func delete() {
        
        // Realm使う宣言！
        let realm = try! Realm()
        
        // 取得したTodoリストのPassedNumber番目をeditData変数に代入
        let editData = todoList[passedNumber]
        
        // 削除のコード（番号を指定）
        try! realm.write {
            realm.delete(editData)
        }
        
        navigationController?.popViewController(animated: true)
    } //削除(CRUDのD)終わり！

}
```

## ◼️ストーリーボードの設定
- ViewControllerにTableViewとTableViewCellを設定します。(identifilerは"Cell")
- AddViewController / EditViewControllerにTextFieldとTextViewを追加します。
- 追加・編集完了ボタンを追加します。
- 今回はこの３画面だけを使用します

## 全体
![スクリーンショット 2021-06-12 10.32.48.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/9f7f3846-60ee-3add-1110-42bd0ff00ca2.png)

## ViewController 

![スクリーンショット 2021-06-12 10.33.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/0a98e8fb-5440-b72c-e9e8-77d769f7b6e6.png)

## AddViewController

![スクリーンショット 2021-06-12 10.33.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/315f8404-b0bd-73e1-3634-fd6ed11dd35f.png)

## EditViewController

![スクリーンショット 2021-06-12 10.33.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/655655/596038c2-8063-d4f3-700b-e9e3e63af4ef.png)


＊この辺の詳細はこちらの記事をご参照ください
👨‍💻[SwiftでTableViewを使ってみよう](https://qiita.com/TD3P/items/cafa8e20029047993025)



# 📱完成！
- 早速buildしてみましょう
- 項目を追加した後に、アプリを終了して、再起動してください
- 再起動時に、追加した項目が表示されていれば、データの永続化が出来ています！



# 📗参考資料
- Realm日本語ドキュメント
  - https://realm.io/jp/docs/swift/latest/
- CocoaPodsの使い方
  - https://www.ukeyslabo.com/development/iosapplication/how-to-use-cocoapods-for-beginner/
  - https://qiita.com/pekocalypse/items/b80f6c343355a872dde6