なるべく純粋なSwiftでアプリを作りたい。
ライブラリはなるべく入れたくない!
そう思った事ないですか?
Swiftには、JSONDecoderと言うJSONをデコードするための標準の機能があります。
このJSONDecoderがとても優れているので、今回記事を書きました。
手始めにJSONのデコードに使うSwiftyJsonを、純粋なSwiftで置き換えた所メリットしかなかったので、ここにメモします。
・パフォーマンスがJsonDecoderの方がSwiftyJsonより優れている。
・依存関係を一つ減らせる。
など。
JSONDecoderの基本的な使い方
1. Decodableを、structへ継承する。
継承するだけで、struct/classをデコード可能にしてくれる優れものです。
import Foundation
struct User: Decodable {
var name: String
var age: Int
}
2. jsonをDataへと変換する。
let json = """
{
"name": "Bob",
"age": 20,
}
"""
let jsonData = json.data(using: .utf8)!
3. JSONDecoderでデコードする。
let user = try JSONDecoder().decode(User.self, from: jsonData)
以上です。
structに、jsonがstructに格納されました。
シンプルで使いやすいですね。
print(user.name) // Bob
print(user.age) // 20
配列内のjsonからデータを取り出す
もちろんルートが配列のJSONもデコード出来る。
また、jsonにかけているキーがある場合、オプショナル型で表現する。
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を使用し、デコード可能にする。
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は、ネストさせる事が出来る。
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のデータ構造を表す事が可能。
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") ]
// )
// ]
// )
// ]