この記事を投稿したものの、この記事が見る方がいないことを祈ります。
僕だってこんな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しているのを確認する必要があったからです。