Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationEventAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
1
Help us understand the problem. What is going on with this article?

More than 1 year has passed since last update.

@Takumi_Mori

Codableに関する覚書

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

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

参考

Codable

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

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パーサーに任せた方がいいんじゃなかろうかとか思い始める。

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

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の場合

{
    "name" : "なまえ",
    "age" : 21,
    "details" : {
        "address" : "渋谷区渋谷"
    }
}
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

1
Help us understand the problem. What is going on with this article?
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
1
Help us understand the problem. What is going on with this article?