Codableに関する覚書

Codable（Decodable）に関して、Modelを作ってるときは覚えているんだけど
忘れてしまうことが多いので、自分用の備忘録的に残しておく。
基本的には手動Codableの書き方。配列形式と、ネスト形式をよく忘れるので。

配列型の場合は`.nestedUnkeyedContainer`、
辞書型の場合は`.nestedContainer`を使います。

## 参考

- 公式ドキュメント : [Encoding and Decoding Custom Types](https://developer.apple.com/documentation/foundation/archives_and_serialization/encoding_and_decoding_custom_types)
- [【Swift】Codableについて備忘録](https://qiita.com/s_emoto/items/deda5abcb0adc2217e86)

## Codable
Codableを親クラスとして指定すると、Encodable + Decodableのメソッドがデフォルトで設定されている。
CodingKeysなどについての詳しいところは、参考記事の方で解説されているので省略

```swift
struct User: Codable {
    let name: String
    let age: Int
    
// ここから以下がデフォルトで定義されている（変更の必要がなければ、書かなくて良い）
    enum CodingKeys: String, CodingKey {
        case name
        case age
    }
}
// 本来ならここから下を書く場合には、UserからCodableのプロトコルは外す
extension User:Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name, forKey: .name)
        try container.encode(age, forKey: .age)
    }
}

extension User:Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        age  = try values.decode(Int.self, forKey: .age)
    }
}
```

## 手動Codable
自動に任せれば楽なんだけど、そうするとModelの形がAPIに引きづられてしまうので使いにくいことも多い。
そこで手動でEncode / Decodeを書く必要が出てくるんだけどこれがちょっと厄介というか・・・。
なんか普通にJSONパーサーに任せた方がいいんじゃなかろうかとか思い始める。

### 配列を手動で解析する場合

```swift
struct User {
    let name: String
    let age: Int
    let friends: [Friend]
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case friends
    }
    
    struct Friend: Codable {
        let name: String
    }
}

extension User: Encodable {
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name,    forKey: .name)
        try container.encode(age,     forKey: .age)
        try container.encode(friends, forKey: .friends)
    }
}

extension User: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        age  = try values.decode(Int.self, forKey: .age)
        
        var friends:[Friend] = []
        var array = try values.nestedUnkeyedContainer(forKey: .friends)
        while(!array.isAtEnd) {
            let info = try array.decode(Friend.self)
            friends.append(info)
        }
        self.friends = friends
    }
}

```

### ネストしている要素を解析する場合

こんなJSONの場合

```json
{
	"name" : "なまえ",
	"age" : 21,
	"details" : {
		"address" : "渋谷区渋谷"
	}
}
```

```swift
struct User {
    let name: String
    let age: Int
    let address: String
    
    enum CodingKeys: String, CodingKey {
        case name
        case age
        case details
    }
}

extension User: Encodable {
    private enum DetailKeys: String, CodingKey {
        case address
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        try container.encode(name,    forKey: .name)
        try container.encode(age,     forKey: .age)
        
        var details = container.nestedContainer(keyedBy: DetailKeys.self, forKey: .details)
        try details.encode(address, forKey: .address)
    }
}

extension User: Decodable {
    init(from decoder: Decoder) throws {
        let values = try decoder.container(keyedBy: CodingKeys.self)
        name = try values.decode(String.self, forKey: .name)
        age  = try values.decode(Int.self, forKey: .age)
        
        let details = try values.nestedContainer(keyedBy: DetailKeys.self, forKey: .details)
        address = try details.decode(String.self, forKey: .address)
    }
}
```

## EOF