【Swift】基礎的な部分だけど理解せずに使っていること

# はじめに
大変お世話になっているこちらの本[Swift実践入門 ── 直感的な文法と安全性を兼ね備えた言語](https://honto.jp/netstore/pd-book_30220833.html)を読み返す度に「これちゃんと理解してなかった」という内容に出会うので、一度まとめてみました。
ありがたいことに、[こちら](https://swift.codelly.dev/guide/swift%E3%81%A8%E3%81%AF/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0%E8%A8%80%E8%AA%9ESwift%E3%81%A8%E3%81%AF.html#swift%E3%81%A8%E3%81%AF)で本の内容（一部？）が公開してありました。

あとは[公式ドキュメント](https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html)も参考に。

# `enum`
### - プロパティ
- コンピューテッドプロパティ
- スタティックプロパティ
が使える
※ `var point = 100`のようなストアドプロパティは使えない
```swift
enum Mahjong {
    case pon
    case chii
    case kan

    // コンピューテッドプロパティを定義
    var claim: String {
        switch self {
        case .pon: return "ポン"
        case .chii: return "チー"
        case .kan: return "カン"
        }
    }

    // スタティックプロパティを定義
    static let points = 25000
}
```

### - メソッド
`enum`は、メソッドを定義することができる。
また、`mutating`メソッドを使うことで`enum`自身を変更することができる。

```swift
enum Mahjong {
    case pon
    case chii
    case kan

    // メソッドを定義
    func claim() -> String {
        switch self {
        case .pon: return "ポン"
        case .chii: return "チー"
        case .kan: return "カン"
    }

    // mutating で変更可能
    mutating func update(mahjong: Mahjong) {
        self = mahjong
    }
}
```

### - デフォルト値
`enum`に型を指定すると`rawValue`でデフォルト値が取得できる
```swift
enum Wind: Int {
    case east    // Wind.east.rawValue: 0
    case south   // Wind.south.rawValue: 1
    case west    // Wind.west.rawValue: 2
    case north   // Wind.north.rawValue: 3
}

enum Mahjong: String {
    case pon     // Mahjong.pon.rawValue: pon
    case chii    // Mahjong.pon.rawValue: chii
    case kan     // Mahjong.pon.rawValue: kan
}

```

`Raw Value`は`case`に値を代入することで定義できる
```swift
enum Wind: Int {
    case east = 10    // Wind.east.rawValue: 10
    case south = 20   // Wind.south.rawValue: 20
    case west = 30    // Wind.west.rawValue: 30
    case north = 40   // Wind.north.rawValue: 40
}

enum Mahjong: String {
    case pon = "ポン"   // Mahjong.pon.rawValue: ポン
    case chii = "チー"  // Mahjong.pon.rawValue: チー
    case kan = "カン"   // Mahjong.pon.rawValue: カン
}

```

### - `allCases`を使う
`CaseIterable`プロトコルに準拠させることで、ケースを配列で取得できる
※`case`はカンマでつなげて書いてもよい

```swift
enum Mahjong: CaseIterable {
  case pon, chii, kan
}
// Mahjong.allCases // [pon, chii, kan]
```

### - `Associated Values`を使う
`Associated Values`を使うと`case`に付属的に関連する値をつけることができる

```swift
enum Mahjong {
    case score(east: Int, south: Int, west: Int, north: Int)

    func data() -> [Int] {
        switch self {
        case .score(let east, let south, let west, let north):
            return [east, south, west, north]
        }
    }
}
```
※全ての値が`let`or`var`で一致している場合は
`case let .score(east, south, west, north)`と書ける。

# `Associated Type`
`Associated Type`を使用すると、1つの型に依存しない抽象的なプロトコルを定義することができ、具体的な型はプロトコルを準拠させるタイミングで指定させることができる。

```swift 
protocol プロトコル {
  associated type 関連型

  var プロパティ名: 関連型
  func メソッド名(引数: 関連型)
}
```

プロトコルを準拠させる側では、`typealias`を使って、具体的な型を指定する。
```swift
struct ProductItem: プロトコル {
  // String型で具体的な型を指定
  typealias 関連型 = String
  var プロパティ名 = "pon"
}
```

# クロージャ

### - `escaping`
escapingをつけることによって、クロージャが関数内部の変数をキャプチャし、関数外のスコープでも変数を保持し実行することができる。

具体的にはクロージャを非同期処理の後に実行したいときなど。
非同期処理を実行する多くの関数は、`completionHandler`としてクロージャ引数を取り、実行が完了するまでクロージャーは呼び出されないので、`escaping`して後で呼び出す必要がある。
```swift
var completionHandlers: [() -> Void] = []
func someFunctionWithEscapingClosure(completionHandler: @escaping () -> Void) {
    completionHandlers.append(completionHandler)
}
```

`escaping`しない場合、クロージャは関数外のスコープで処理を実行できないため、例えばこうなる。
```swift
func someFunctionWithoutEscapingClosure(completionHandler: () -> Void) {
    completionHandlers()
}
```

### - キャプチャとキャプチャリストとは
クロージャのキャプチャとは、クロージャが定義されたスコープに存在する変数や定数への参照を、クロージャ内のスコープでも保持することをいう。
デフォルトでは、このキャプチャはクラスのインスタンスへの強参照になるため、クロージャが解放されない限りキャプチャされたクラスのインスタンスが解放されない。

このような場合、キャプチャリストを用いることで弱参照を持つことができる。キャプチャを弱参照にすると、クロージャの解放状況に依存せずクラスのインスタンスの解放が行われる。また循環参照の解消にも役立つ。

キャプチャリストを定義するには、クロージャの引数の定義の前に`[ ]`を追加し、内部に`weak`キーワードもしくは`unowned`キーワードと変数名もしくは定数名の組み合わせを列挙する。

```swift
{ [ weak or unowned 変数名 or 定数名] (引数) -> 戻り値 in
    クロージャの呼び出し時に実行される文
}
```

※`weak`と`unowned`の違いはOptional型かどうかで、`unowned`を使い変数がnilの場合は実行時エラーが発生する

# おわりに
`Associated Type`はなんとなくでも使えてもないかも、、、`enum`と`[weak self]`はよく使っていますが理解はできてなかったようで、まとめたことによりやっと理解できました。

今回の内容は、こちらの続き

https://qiita.com/yoshitaka/items/2d6adfcdec366dd42ba0

でしたが、まだ分かっていないことがありそうなので、継続して読み返していきたいと思います。

# 参考

https://swift.codelly.dev/guide/%E5%88%97%E6%8C%99%E5%9E%8B/#%E3%83%97%E3%83%AD%E3%83%91%E3%83%86%E3%82%A3

https://swift.codelly.dev/guide/%E3%83%97%E3%83%AD%E3%83%88%E3%82%B3%E3%83%AB/#%E9%96%A2%E9%80%A3%E5%9E%8B-associated-type

https://swift.codelly.dev/guide/%E3%82%AF%E3%83%AD%E3%83%BC%E3%82%B8%E3%83%A3/#%E5%BE%AA%E7%92%B0%E5%8F%82%E7%85%A7-%E5%BC%B7%E5%8F%82%E7%85%A7

https://docs.swift.org/swift-book/LanguageGuide/TheBasics.html