Swiftの標準関数でJSONをデコードする。SwiftyJSONからの脱却。

# なるべく純粋なSwiftでアプリを作りたい。
ライブラリはなるべく入れたくない！
そう思った事ないですか？

Swiftには、JSONDecoderと言うJSONをデコードするための標準の機能があります。
このJSONDecoderがとても優れているので、今回記事を書きました。

手始めにJSONのデコードに使うSwiftyJsonを、純粋なSwiftで置き換えた所メリットしかなかったので、ここにメモします。
・パフォーマンスがJsonDecoderの方がSwiftyJsonより優れている。
・依存関係を一つ減らせる。
など。

## JSONDecoderの基本的な使い方

### 1. Decodableを、structへ継承する。
継承するだけで、struct/classをデコード可能にしてくれる優れものです。

```swift
import Foundation

struct User: Decodable {
  var name: String
  var age: Int
}
```
### 2. jsonをDataへと変換する。

```swift

let json = """
{
  "name": "Bob",
  "age": 20,
}
"""
let jsonData = json.data(using: .utf8)!
```

### 3. JSONDecoderでデコードする。

```swift

let user = try JSONDecoder().decode(User.self, from: jsonData)
```

以上です。
structに、jsonがstructに格納されました。
シンプルで使いやすいですね。

```swift

print(user.name) // Bob
print(user.age) // 20
```

## 配列内のjsonからデータを取り出す
もちろんルートが配列のJSONもデコード出来る。
また、jsonにかけているキーがある場合、オプショナル型で表現する。

```swift

import Foundation

let json = """
[
    {
        "name": "Bob",
        "age": 30,
        "password": "foo"
    },
    {
        "name": "Ben",
        "age": 20
    }
]
""".data(using: .utf8)!

struct User: Decodable {
    var name: String
    var age: Int
    var password: String?
}

let users = try JSONDecoder().decode([User].self, from: json)

for user in users {
    print(user)
}
// 結果
// User(name: "Bob", age: 30, password: Optional("foo"))
// User(name: "Ben", age: 20, password: nil)
```

## キーの名前を変更する
jsonのキーと、swiftのオブジェクトのキーの名前が異なる事がある。
例えばjsonのキーがuser_id、swiftオブジェクトのキーがuserIdだった時などだ。
このままではデコード出来ないので、Decodableの、CodingKeys　enumを使用し、デコード可能にする。

```swift

import Foundation

let json = """
[
    {
        "name": "Bob",
        "age": 30,
        "password": "foo",
        "user_id": 1
    },
    {
        "name": "Ben",
        "age": 20,
        "user_id": 2
    }
]
""".data(using: .utf8)!

struct User: Decodable {
    var name: String
    var age: Int
    var password: String?
    var userId: Int
    
    private enum CodingKeys: String, CodingKey {
        case name
        case age
        case password
        case userId = "user_id"
    }
}

let users = try JSONDecoder().decode([User].self, from: json)

for user in users {
    print(user)
}
```

無事に、user_idを、userIdへとマッピングする事が出来ました。

## ネストしたjsonからデータを取り出す
Decodableは、ネストさせる事が出来る。

```swift

struct User: Decodable {
    let name: String
    let children: [Child]
    
    struct Child: Decodable {
        let name: String
        let teachers: [Teacher]
        
        struct Teacher: Decodable {
            let name: String
        }
    }
}
```

そのため、簡単にネストしたJSONのデータ構造を表す事が可能。

```swift
import Foundation
let json = """
[
    {
        "name": "A",
        "children": [
            {
                "name": "B",
                "teachers": [
                    {
                        "name": "C"
                    }
                ]
            }
        ]
    },
    {
        "name": "E",
        "children": [
            {
                "name": "F",
                "teachers": [
                    {
                        "name": "G"
                    },
                    {
                        "name": "I"
                    }
                ]
            }
        ]
    }
]
""".data(using: .utf8)!

let users = try JSONDecoder().decode([User].self, from: json)
// [
//   User(
//     name: "A",
//     children: [
//       Child(
//         name: "B",
//         teachers: [ Teacher(name: "C") ]
//       )
//     ]
//   ),
//   User(
//     name: "E",
//     children: [
//       Child(
//         name: "F",
//         teachers: [ Teacher(name: "G"), Teacher(name: "I") ]
//       )
//     ]
//   )
// ]
```