Swiftのprotocol,enum,struct,classをまとめてみた

# はじめに
なんとなく使ってる`protocol` `enum` `struct` `class`についてガチガチに調べました

## 目次
1. protocolに関して
2. enumに関して
3. structに関して
4. classに関して
5. `値型`と`参照型`の違い
6. structとclassの使い分け
7. 用語

### `protocol`に関して
参考にしたサイトでは「Swiftのプロトコルは、型のインターフェースを定義するものです。」と書いてありました。
- **型のインターフェイス**とは？
たとえば、ある型(クラスや構造体)がどんな機能や性質をもっているか説明するもの
よくわからないので実装例を見ていきます。
```swift
protocol Playable {
  func play()
}

struct Toy: Playable {
  func play() {
    print("おもちゃで遊ぶよん")
  }
}
```
さっき書いた説明に当てはめると「構造体(`Toy`)が`play()`という機能/性質を持ってるよ」ってことです。

- でもこれ`Playable`つくんなくて良くない?
おっしゃる通りだと思います。
しかし、処理が増えてくるとprotocolを作らないとめんどくさくなります
例えば`protocol`なしだと
```swift
struct Toy {
    func play() {
        print("おもちゃで遊ぶよん")
    }
}

struct Game {
    func play() {
        print("ゲームで遊ぶよん")
    }
}

// `Toy`型専用の関数
func startPlayingToy(toy: Toy) {
    toy.play()
}

// `Game`型専用の関数
func startPlayingGame(game: Game) {
    game.play()
}

let toy = Toy()
let game = Game()

startPlayingToy(toy: toy)  // 出力: おもちゃで遊ぶよん
startPlayingGame(game: game) // 出力: ゲームで遊ぶよん
```
`startPlayingToy()`と`startPlayingGamestartPlayingGame`の2つ関数を作らないといけないのですが`protocol`を使うと
```swift
protocol Playable {
    func play()
}

struct Toy: Playable {
    func play() {
        print("おもちゃで遊ぶよん")
    }
}

struct Game: Playable {
    func play() {
        print("ゲームで遊ぶよん")
    }
}

func startPlaying(item: Playable) {
    item.play()
}

let toy = Toy()
let game = Game()

startPlaying(item: toy)  // 出力: おもちゃで遊ぶよん
startPlaying(item: game) // 出力: ゲームで遊ぶよん
```
1つの関数で済むようになります。

- その他、`ObservableObject`や`Decodable`もprotocolの1つですね。

### `enum`に関して
列挙型とは、値型の一種で、関連する値のグループに共通の型を定義してまとめたもの
これは例を見れば簡単です
```swift
enum Game {
  case monsterHunter
  case dragonQuest
  case smashBros
  case splatoon
}
```
こんな感じで`Game`の中にモンハン、ドラクエ、スマブラ、スプラトゥーンが入ってる感じですね。
```swift
func printGameMessage(game: Game) {
    switch game {
    case .monsterHunter:
        print("モンスターハンターで狩りをしよう！")
    case .dragonQuest:
        print("ドラゴンクエストのRTAが待っている！")
    case .smashBros:
        print("スマッシュブラザーズでバトルしていらつこう！")
    case .splatoon:
        print("スプラトゥーンで味方にイラつこう！")
    }
}
```
使う時はこんな感じで`Game.(caseで決めた値)`のように設定します。

### `struct`に関して
簡単にいうと継承できない値渡しの、変数や関数をまとめた固まりみたいなもの

### `class`に関して
継承できる参照渡しの、変数や関数をまとめた固まりみたいなもの

### `値型`と`参照型`の違い
ここまで読んでくれてる人に「値渡しやら参照渡しやらうっとうしいわ」みたいなことを言われそうなのでまずこちらを解説していきます。
**まずは例から**
**値型**
```swift
struct Woman {
  var name: String
  var isCute: Bool
}

var woman1 = Woman(name: "長濱ねる", isCute: true)

var woman2 = woman1

woman2.name = "フワちゃん"
woman2.isCute = false

print("woman1")
print(woman1)
print("woman2")
print(woman2)
```
上の例で実行すると
```
woman1
Woman(name: "長濱ねる", isCute: true)
woman2
Woman(name: "フワちゃん", isCute: false)
```
と出力されます。
**参照型**
一方で
```swift
class Woman {
  var name: String
  var isCute: Bool
  
  init(name: String, isCute: Bool) {
    self.name = name
    self.isCute = isCute
  }
}

var woman1 = Woman(name: "長濱ねる", isCute: true)

var woman2 = woman1

woman2.name = "フワちゃん"
woman2.isCute = false

print("woman1: \(woman1.name), isCute: \(woman1.isCute)")
print("woman2: \(woman2.name), isCute: \(woman2.isCute)")

```
と`struct`で書いていたところを`class`で書き直すと
```
woman1: フワちゃん, isCute: false
woman2: フワちゃん, isCute: false
```
とprintされます。

**まとめ**
違いが分かりましたでしょうか？

structは`var woman2 = woman1`のタイミングで`woman1`のコピーを渡してる感じです。
コピーされた紙に書いたものはコピーする前の紙には反映されないですよね？
それと同じことをしてます。

classは`var woman2 = woman1`のタイミングでコピーではなくそのものを渡してます。
コピー取らずにそのままの紙に書き込んでるイメージです。
なので
```swift
woman2.name = "フワちゃん"
woman2.isCute = false
```
の時点でwoman1も書き換わり、お前は偉くないので⚪︎んでくださーいされます。

### `struct`と`class`の使い分け
classを使うとき
- ViewModel・・・理由は、画面の状態やデータを複数のViewで共有したり、変更を他の場所に通知する必要があるため
- Usecase・・・理由は、ビジネスロジックを持ち、状態の変更や複数箇所で共有が必要になるためclassが適している
- Repository・・・理由は、APIやデータベースとのやり取りを行い、同じインスタンスでデータの管理が必要なことが多いためclassが適している
- APIClient・・・理由は、APIとの通信を管理し、単一のインスタンスでネットワーク接続やリクエストの管理を行う必要があるためclassが適している

structを使うとき
- Model・・・理由は、データを保持するだけの役割が多く、軽量なデータ構造を扱うため、コピーで扱えるstructが適している

あくまで一般的になので状況に応じて臨機応変に変えていくことが大事(丸投げ)
### 用語

## 参考文献
**protocol**
https://swift.codelly.dev/guide/%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB/

**enum**
https://swift.codelly.dev/guide/%E5%88%97%E6%8C%99%E5%9E%8B/

**struct**
https://qiita.com/yuinchirn/items/98b568d595650eca3334
https://qiita.com/motoki418/items/156182ec8750e7b567b9
https://zenn.dev/egg_head/articles/fd48844e86ad7b

### `値型`と`参照型`の違い
https://www.youtube.com/watch?v=gFVpGw-X7Fg