【Swift】CodableでJSONをDecodeする方法

この記事で紹介するコードはSwift5、iOS13で動かした時の物です。

JSONをパースする時にはCodableを継承したStructを作ります。

以下のような感じ。

struct Rest:Codable {
    let name:String
}

例えば、{"name":"hoge"}のJSONが与えられた時には以下のコードでパースできます。

let decoder = JSONDecoder()
let json = try decoder.decode(Rest.self, from: data)

上記の例は、JSONの”name”がString型で返ってくることが確定している場合は問題がありませんが、JSON内の要素の型が時々変わるもの場合にはエラーが出ます。

以下の例を見てみよう。

struct Rest:Codable {
    budget:Int
}

budgetの値がIntで返ってくる時もあればStringで返ってくることがある。

例えば、{"budget":3000} or {"budget":""}のケース。

Stringが返ってきた場合には上記の構造体ではパースした時にエラーが出る。

このようなイレギュラーなケースに対応するためは、手動でDecode処理を実装する必要がある。

Codableを継承している場合、Decodeはinit内で行う。

CodingKeysにキー名を羅列し、キー名を指定してデコードする。

以下の実装例を見てみよう。

struct Rest:Codable {
    let budget:Int
    
    private enum CodingKeys : String, CodingKey {
        case budget
     }

     init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        let budgetInt = try? container.decode(Int.self, forKey: .budget)
        let budgetString = try? container.decode(String.self, forKey: .budget)
        // Intでデコードできなかった場合には0を代入する。
        self.budget = budgetInt ?? (budgetString == "" ? 0 : 0)
     }
}
  1. `CondingKeys`にbudgetを追加。
  2. budgetをInt型とString型の両方でデコードする。
  3. Int型でデコードできた場合にはそのまま代入、できなかった場合には0を代入する。

こんな感じ。

終わり。

ABOUTこの記事をかいた人

個人アプリ開発者。Python、Swift、Unityのことを発信します。月間2.5万PVブログ運営。 Twitter:@yamagablog