Итак, у нас есть два типа ответов JSON в нашем API:
{
"data": { } // some object in here
"meta": { } // an object in here
}
и
{
"data": [ ] // array of objects
"meta": { } // an object in here
}
Для их декодирования мы используем JSONDecoder () и следующую общую структуру ответа:
public struct Response<T: Codable>: Codable {
public let data: T
public let meta: Meta?
}
Это прекрасно работает с Swift 4.0, используя .map(Response<[MyObject]>.self)
или .map(Response<MySingleObject>.self)
, но по какой-то причине это больше не работает со Swift 4.1 и Xcode 9.3. Похоже, он вообще не отображает «данные» и поэтому считает, что список [MyObject]
находится на первом уровне.
dataCorrupted: Swift.DecodingError.Context
▿ codingPath: 3 elements
- CodingKeys(stringValue: "data", intValue: nil)
▿ _JSONKey(stringValue: "Index 0", intValue: 0)
- stringValue: "Index 0"
▿ intValue: Optional(0)
- some: 0
- CodingKeys(stringValue: "creationDate", intValue: nil)
- debugDescription: "Date string does not match format expected by formatter."
Обратите внимание, что "creationDate" является свойством MyObject
. Формат даты определенно правильный (установлен на .formatted(customFormatter)
в декодере), так как он работает с Swift 4.0 в Xcode 9.2
Как мы можем продолжать вести себя так же со Swift 4.1? Цель здесь состояла в том, чтобы не создавать типизированный тип Response
для каждого ответа API, а использовать вместо него универсальный тип, потому что единственное различие заключается в типе объекта ответа и в том, что иногда он возвращает список, а иногда один объект под data
. * 1024. *
Также связано: есть ли способ обеспечить, что если мы используем Response<[MyObject]>.self
, то MyObject
также должно соответствовать Codable
?
Заранее спасибо.
Edit:
Код ниже отображается правильно в Xcode 9.2 и Swift 4, но не отображается (создает ноль) в Xcode 9.3 и Swift 4.1
public struct MyObject: Codable {
public let creationDate: Date
enum CodingKeys: String, CodingKey {
case creationDate = "creation_date"
}
}
public struct Response<T: Codable>: Codable {
public let data: T
public let meta: Meta?
}
public struct Meta: Codable {
public let count: Int?
}
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-mm-dd HH:mm:ss"
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(formatter)
let jsonDataSingle: Data = """
{
"data": { "creation_date": "2018-04-29 18:00:11" },
"meta": null
}
""".data(using: .utf8)!
let jsonDataList: Data = """
{
"data": [{ "creation_date": "2018-04-10 17:00:11" }, { "creation_date": "2018-04-29 18:00:11" }],
"meta": null
}
""".data(using: .utf8)!
let singleObject = try? decoder.decode(Response<MyObject>.self, from: jsonDataSingle)
dump(singleObject)
let listOfObjects = try? decoder.decode(Response<[MyObject]>.self, from: jsonDataList)
dump(listOfObjects)