通用解码器停止使用 swift 4.1
Generic Decodable stopped working with swift 4.1
所以我们 API 中有两种类型的 JSON 响应:
{
"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。看起来它根本没有映射 "data",因此认为 [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 in Xcode 9.2
我们如何才能与 Swift 4.1 保持相同的行为?这里的目标是不为每个 API 响应创建类型化的 Response
类型,而是使用泛型,因为唯一的区别是响应对象类型,有时它 returns 一个列表,有时data
.
下面的单个对象
也相关:如果我们使用 Response<[MyObject]>.self
是否有办法强制执行 MyObject
也必须符合 Codable
?
提前致谢。
编辑:
下面的代码在 Xcode 9.2 和 Swift 4 中正确映射,但在 Xcode 9.3 和 Swift 4.1[=26= 中不映射(创建 nil) ]
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)
我没有收到任何错误。请post吧。作为练习,我添加了 CustomStringConvertible 一致性并将 dump 替换为 print.
extension Response: CustomStringConvertible {
public var description: String {
return "data = \(data) | meta = \(meta)"
}
}
extension MyObject: CustomStringConvertible {
public var description: String {
return "date = \(creationDate)"
}
}
我正在使用通过 App Store 发布的 Xcode 9.3、Swift 4.1 版本 9E145。
所以我们 API 中有两种类型的 JSON 响应:
{
"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。看起来它根本没有映射 "data",因此认为 [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 in Xcode 9.2
我们如何才能与 Swift 4.1 保持相同的行为?这里的目标是不为每个 API 响应创建类型化的 Response
类型,而是使用泛型,因为唯一的区别是响应对象类型,有时它 returns 一个列表,有时data
.
也相关:如果我们使用 Response<[MyObject]>.self
是否有办法强制执行 MyObject
也必须符合 Codable
?
提前致谢。
编辑:
下面的代码在 Xcode 9.2 和 Swift 4 中正确映射,但在 Xcode 9.3 和 Swift 4.1[=26= 中不映射(创建 nil) ]
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)
我没有收到任何错误。请post吧。作为练习,我添加了 CustomStringConvertible 一致性并将 dump 替换为 print.
extension Response: CustomStringConvertible {
public var description: String {
return "data = \(data) | meta = \(meta)"
}
}
extension MyObject: CustomStringConvertible {
public var description: String {
return "date = \(creationDate)"
}
}
我正在使用通过 App Store 发布的 Xcode 9.3、Swift 4.1 版本 9E145。