问题描述
我处理的 API 返回:
{
"title": "Hello World"
}
或
{
"title": [{
"text": "Hello World"
}]
}
我的想法是拥有一个带有自定义解码器的 struct TitleStringValue
,如下所示:
struct TitleStringValue: Decodable {
let text: String
struct TitleStringValueInner: Decodable {
let text: String
}
init(from decoder: Decoder) throws {
if let stringContainer = try? decoder.singleValueContainer() {
text = try stringContainer.decode(String.self)
} else {
var arrayContainer = try decoder.unkeyedContainer()
text = try arrayContainer.decode(TitleStringValueInner.self).text
while !arrayContainer.isAtEnd {
_ = try? arrayContainer.decode(TitleStringValueInner.self)
}
}
}
}
struct MyResult: Decodable {
let title: TitleStringValue
}
但在 title 由数组组成的情况下,TitleStringValue init(from decoder: Decoder)
永远不会被调用,因为解码器之前失败,遇到一个数组,它需要一个值类型。
有没有办法解决这个问题?
我可以在 MyResult 结构的级别上实现解码,但这意味着每个具有 TitleStringValue
的结构都需要一个自定义解码器,所以我更愿意在 TitleStringValue 级别上实现它。
解决方法
我的建议是在这两种情况下都保留 title
属性。
首先尝试解码 String
。如果这失败解码 Text
数组(我保持名称简单)获取第一项并将 text
值分配给 title
。
struct Title: Decodable {
struct Text : Decodable { let text : String }
let title : String
private enum CodingKeys : String,CodingKey { case title }
init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
do {
title = try container.decode(String.self,forKey: .title)
} catch DecodingError.typeMismatch {
let textArray = try container.decode([Text].self,forKey: .title)
title = textArray.first?.text ?? ""
}
}
}
,
这里的问题是 singleValueContainer 也可用于解码数组。因此,您得到的错误是由 try
的 init(from:)
函数内的第二个 TitleStringValue
而不是之前产生的。
话虽如此,您可以像这样进一步简化您的自定义解码:
struct TitleStringValue: Decodable {
let text: String
struct TitleStringValueInner: Decodable {
let text: String
}
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let string = try? container.decode([TitleStringValueInner].self).first?.text {
text = string
} else {
text = try container.decode(String.self)
}
}
}