【Swift5】Realmでデータを保存する

# Realmとは
- モバイル版のデータベース管理システム
- 公式ドキュメントは[こちら](https://www.mongodb.com/docs/realm-legacy/docs/swift/latest/)
# メリット
- ライブラリRealmSwiftを使用すると、アプリのモデルレイヤーで高速かつ効率的に記述できる。
- Realm Stadioアプリでデータベース管理ができる。
- データの保存、削除、検索などデータを操作しやすい
- アプリ内にデータを保存しているので、オフラインでも動くし、サーバーの負荷軽減にもつながる。

# デメリット
- Structやenumが使えない。書き方に工夫が必要。
- Realm特有の仕様があるから思わぬとこでハマる。List型とか

# Realmの導入
- pod installする
```
pod 'RealmSwift'
 ```


# 実装
- 今回は、PersonモデルとPokemonモデルを用意し、Personモデルに入っているPokemonモデルの配列にHitokageとZenigameとFusigidaneのデータを入れ、データがきちんとアプリ内に保存されているかログ出力で確認することを目標にします。
## 1.簡単にUIを作る
- とりあえずUIButton並べる。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1161345/97b21bfe-03a4-12f0-92e7-1ebc883cf56f.png" width=400>


## 2.Model作成
```swift:Pokemon.swift
import RealmSwift

@objcMembers
class Pokemon: Object {
    dynamic var id = 0
    dynamic var name = ""
}
```

```swift:Person.swift
import RealmSwift

@objcMembers
class Person: Object {
    dynamic var id = 0
    dynamic var name = ""
    var pokemon = List<Pokemon>()
}
```

## 3.ViewControllerの作成
```swift:ViewController.swift

import UIKit
import RealmSwift

class ViewController: UIViewController {

    let person = Person()
    let realm = try! Realm()

    override func viewDidLoad() {
        super.viewDidLoad()

    }

    @IBAction func tapHitokageButton(_ sender: Any) {
        let pokemon = Pokemon()
        pokemon.id = 1
        pokemon.name = "ヒトカゲ"

        try! realm.write {
            realm.add(pokemon)
            person.pokemon.append(pokemon)
            realm.add(person)
        }
    }

    @IBAction func tapZenigameButton(_ sender: Any) {
        let pokemon = Pokemon()
        pokemon.id = 2
        pokemon.name = "ゼニガメ"

        try! realm.write {
            realm.add(pokemon)
            person.pokemon.append(pokemon)
            realm.add(person)
        }
    }

    @IBAction func tapFusigidaneButton(_ sender: Any) {
        let pokemon = Pokemon()
        pokemon.id = 3
        pokemon.name = "フシギダネ"

        try! realm.write {
            realm.add(pokemon)
            person.pokemon.append(pokemon)
            realm.add(person)
        }
    }

    @IBAction func tapConfirmButton(_ sender: Any) {
        let resultPokemon = realm.objects(Pokemon.self)
        print(resultPokemon)
        let resultPerson = realm.objects(Person.self)
        print(resultPerson)
    }
}



```
# 完成
#### 動作確認手順
- 1 ヒトカゲボタン→ゼニガメボタン→フシギダネボタン→手持ちのポケモン確認ボタンを順番に押す
- 2 ログ出力確認↓結果
```
Results<Pokemon> <0x7fbce80117c0> (
	[0] Pokemon {
		id = 1;
		name = ヒトカゲ;
	},
	[1] Pokemon {
		id = 2;
		name = ゼニガメ;
	},
	[2] Pokemon {
		id = 3;
		name = フシギダネ;
	}
)
Results<Person> <0x7fbce6f1c8f0> (
	[0] Person {
		id = 0;
		name = ;
		pokemon = List<Pokemon> <0x600000680a50> (
			[0] Pokemon {
				id = 1;
				name = ヒトカゲ;
			},
			[1] Pokemon {
				id = 2;
				name = ゼニガメ;
			},
			[2] Pokemon {
				id = 3;
				name = フシギダネ;
			}
		);
	}
)

```
こうして見事にrealm.objectsメソッドで、Personモデルの中にPokemonモデルのヒトカゲ、ゼニガメ、フシギダネのデータが保存されていることを確認できました。
ポケモンゲットだぜ！


# はまった点
・PersonモデルのList型のPokemonの配列にうまくpokemonのidやnameなどのデータが入らなかった。
→List型とArray型の変換する？、LinkingObjectsを使う？プライマリーキーのidをoverrideする？とか色々調べて試したけどうまくいかなかった。
#### 解決策：普通にappendするだけだった。
```
        try! realm.write {
            realm.add(pokemon)
            person.pokemon.append(pokemon)
            realm.add(person)
        }
```
pokemonModelのデータをRealmにaddで保存して、personモデルにアクセスしたList型のpokemon変数に保存したpokemonModelのデータをappendする。その後にpersonモデルもaddすれば保存できた。