由于[AnyHashable: Any]
(我需要它),我必须实现init(from:)
和encode(to:)
。但当我运行它时,它无法解码数组值的属性:
typeMismatch(Swift.String,Swift.DecodingError.Context(codingPath:[_JSONKey(stringValue:“items”,intValue:nil)],debugDescription:“应解码字符串,但找到的却是数组。",underlyingError:(无))
这是你可以在Playground中运行的代码:
struct ServerResponse: Codable {
var headers: [AnyHashable: Any]?
var items: [Item]?
enum CodingKeys: String, CodingKey {
case items, headers
}
public init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: ServerResponse.CodingKeys.self)
items = try container.decode([Item].self, forKey: ServerResponse.CodingKeys.items)
let singleValueContainer = try decoder.singleValueContainer()
let stringDictionary = try singleValueContainer.decode([String: String].self)
headers = [:]
for (key, value) in stringDictionary {
headers?[key] = value
}
}
public func encode(to encoder: Encoder) throws {
let stringDictionary: [String: String] = Dictionary(
uniqueKeysWithValues: headers?.map {("\($0)", "\($1)")} ?? []
)
var singleValueContainer = encoder.singleValueContainer()
try singleValueContainer.encode(stringDictionary)
var container = encoder.container(keyedBy: ServerResponse.CodingKeys.self)
try container.encode(items, forKey: ServerResponse.CodingKeys.items)
}
struct Item: Codable {
let name: String
}
}
let testData = """
{
"items": [
{"name": "John"},
{"name": "Duo"}
]
}
""".data(using: .utf8)!
let decoder = JSONDecoder()
do {
let response = try decoder.decode(ServerResponse.self, from: testData)
print(response)
} catch {
print(error)
}
它有什么问题?为什么它抱怨得到String
,而我已经把一个数组?如果我从结构体中删除头,并符合Codable
一切正常。
1条答案
按热度按时间vddsk6oq1#
这里的问题在于如何尝试从这个顶级字典中提取项目,通过尝试将其解码为字典。具体来说,
使用特定的JSON负载,
singleValueContainer
在这里结束这样做是有效的,但是当你试图将容器的内容解码为
[String: String]
时,你是在 * Assert * 你期望容器包含一个特定的字典,该字典具有String
键和String
值;然而,items
键的值 * 不是 * 字符串,而是数组。当你有一个包含任意值的集合时,提取其内容的正确方法是使用带键的容器。具体来说,你可以使用一个带键的容器,其键类型可以接受 * 任何 *
String
或Int
值,如下所示:使用这种编码键类型,您可以请求
decoder
作为另一个带键的容器-这一次,键可以是任意的:诀窍是,现在,
untypedContainer
中的 * 值 * 不会被Assert为任何类型,直到你尝试解码它们。然后你可以迭代untypedContainer.allKeys
(与目前迭代stringDictionary
相同),对于每个键,你可以决定如何将decode(_:forKey:)
从容器中取出。你可以:1.尝试解码一个
String
,如果得到一个DecodinerError.typeMismatch
错误,只需跳过键值对即可。1.检查每个键的值,如果你有已知的键(或者匹配某种模式的键,或者类似的键),那么只解码这些键
例如: