LoginSignup
2
1

More than 5 years have passed since last update.

CodableでarrayにもdictionaryにもなるAPIに遭遇した時の対処法

Posted at

この記事を投稿したものの、この記事が見る方がいないことを祈ります。
僕だってこんなAPIに遭遇したくなかったし、遭遇するつもりもありませんでした。

hoge.swift
struct HourTable: Decodable {
  let fuga: String
  let minuteTables: [MinuteTable]
  enum CodingKeys: String, CodingKey {
    case fuga = "Fuga"
    case minuteTable = "MinuteTable"
  }
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    fuga = try container.decode(String.self, forKey: .fuga)
    minuteTables = hoge(container: container)
  }
}

func hoge(container: KeyedDecodingContainer<HourTable.CodingKeys> ) -> [MinuteTable] {
  let minuteTables = try? container.decodeIfPresent([MinuteTable].self, forKey: HourTable.CodingKeys.minuteTable)
  let minuteTable = try? container.decodeIfPresent(MinuteTable.self, forKey: HourTable.CodingKeys.minuteTable)

  if let minuteTables = minuteTables {
    return minuteTables ?? []
  } else if let minuteTable = minuteTable, let response = minuteTable {
    return [response]
  } else {
    return []
  }
}

struct MinuteTable: Decodable {
  let minute: String
  private enum CodingKeys: String, CodingKey {
    case minute = "Minute"
  }
  init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    minute = try container.decode(String.self, forKey: .minute)
  }
}

この問題が発生した理由として時刻表のAPIを受け取る時に時刻の時間(hour)と分(minute)の部分が別のテーブルになっており、例えば1時間に一本しかない時間帯の時刻表はminuteTableが1つしかないのでdictionary型(jsonで{}で囲まれているもの)で返していて、1時間に何本もあるものは当たり前ですがarray型(jsonで[]で囲まれているもの)で返していました。そのため上のコードのような対処が必要でした。

わざわざfuncを利用し、関数にした後、initの中に代入しているのはthrowsを利用していることでletで定義したものすべてがちゃんとその数の分だけdocodeしているのを確認する必要があったからです。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1