[iOS] Decodable でJSONをデコードする時に要素の型を変換する

前提条件

Xcode: 12.1
Swift 5.3

やりたいこと

以下のようなJSONデータがあったとします。

{
    "食品名":"肉類",
    "食材": "鶏肉, 豚肉, 牛肉"
}

これを Decodable で何もいじらずデコードする場合、型は以下のようになります。

struct Food: Decodable {
    var 食品名: String
    var 食材: String
}

Food.食材 には "鶏肉, 豚肉, 牛肉" という String が入ります。
イケてないので、これを以下のような String の配列として扱いたいです!

struct Food: Decodable {
    var 食品名: String
    var 食材: [String]
}

前提としてデコード処理は以下のように呼び出しています。

        let food = try! JSONDecoder.init().decode(
            Food.self,
            from: data
        )

まずは最終的なコード

struct Food: Decodable {
    var 食品名: String
    var 食材: [String]
    
    enum コーディングキー: String, CodingKey {
        case 食品名
        case 食材
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: コーディングキー.self)
        
        食品名 = try container.decode(String.self, forKey: .食品名)
        let 食材String = try container.decode(String.self, forKey: .食材)
        食材 = 食材String.components(separatedBy: ",")
    }
}

JSONが日本語なので、コードもなんとなくそれに合わせて日本語にしています🤔
問題なく動作します。

自前のデコード処理が必要

ということで、以下順番にデコード処理を書いていきます。

CodingKey に準拠した enum を用意する

まず Food 構造体に、CodingKey プロトコルに準拠させた enum を追加します。

struct Food: Decodable {
    var 食品名: String
    var 食材: [String]
    
    enum コーディングキー: String, CodingKey {
        case 食品名
        case 食材
    }
}

この enum はJSONデータをデコードする際にキーとして利用します(CodingKey の読んで字の如く)。
JSONのキー名と同じ文字列を case に定義します。

ちなみに、デコードで実際に利用するのは enum の rawValue であるという理解がより正しそうです。
ですので、rawValue に別の文字列を定義することでJSONのキー名と異なるプロパティ名でデコードできる、
ということになりますが、それはまた別の機会に。。

デコード用の初期化メソッドを用意する

あとは以下のようにFood構造体の初期化メソッドを定義してやればOKです!

    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: コーディングキー.self)
        
        食品名 = try container.decode(String.self, forKey: .食品名)
        let 食材String = try container.decode(String.self, forKey: .食材)
        食材 = 食材String.components(separatedBy: ",")
    }

try values.decode(String.self, forKey: .食材)"鶏肉, 豚肉, 牛肉" を文字列として 食材String に取り出した後、
, を区切り文字にして配列に分解しています!

これで文字列を配列に変更してパースできました🙌


さて、デコードできたはいいですが、init(from decoder: Decoder) throws で処理しているので、
全てのデコード処理を自前で書く必要があります。

要素の数が増えれば増えるほど記述するコストが増えてしまいます。

ある程度複雑な構造の場合、自前で全てデコード処理を書くのはつらいです。

そこで以下の記事にて、要素の一部のみ独自のデコード処理を適用する方法を書いていきます!
[iOS] Decodable でJSONをデコードする時に要素の型を変換する その2 KeyedDecodingContainer のエクステンションで一部の要素にのみ独自のデコード処理を適用する

最後に

これだけなら割と簡単ですね、お疲れ様でした!

[iOS] Decodable でJSONをデコードする時に要素の型を変換する」への1件のフィードバック

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト /  変更 )

Google フォト

Google アカウントを使ってコメントしています。 ログアウト /  変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト /  変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト /  変更 )

%s と連携中

%d人のブロガーが「いいね」をつけました。