Swift自定义Encoder/Decoder解码数组失败:预期数组却发现字符串
问题根源
你在自定义init(from:)时犯了两个关键错误:
- 错误使用
singleValueContainer:你尝试用它把整个JSON解码成[String: String],但你的JSON包含items数组字段,整个结构是混合了数组值的字典,根本无法被解码成纯字符串字典。 - 解码器状态冲突:先通过keyed container解码
items后,再调用singleValueContainer会干扰解码器的内部状态,导致后续解码逻辑混乱。
修复方案
核心思路是:从对应字段解码headers,而非尝试解码整个JSON结构;编码时用keyed container生成正确的JSON结构,而非单一值容器。
修改后的完整代码:
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: CodingKeys.self) // 解码items字段 items = try container.decodeIfPresent([Item].self, forKey: .items) // 从headers字段解码字符串字典,转换为[AnyHashable: Any] if let stringHeaders = try container.decodeIfPresent([String: String].self, forKey: .headers) { headers = stringHeaders.reduce(into: [AnyHashable: Any]()) { result, pair in result[AnyHashable(pair.key)] = pair.value } } } public func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) // 编码items字段 try container.encode(items, forKey: .items) // 将[AnyHashable: Any]转换为[String: String]后编码headers字段 guard let headers = headers else { return } let stringHeaders = headers.reduce(into: [String: String]()) { result, pair in guard let key = pair.key as? String, let value = pair.value as? String else { return } result[key] = value } try container.encode(stringHeaders, forKey: .headers) } struct Item: Codable { let name: String } } // 测试代码(可添加headers字段测试完整逻辑) let testData = """ { "items": [ {"name": "John"}, {"name": "Duo"} ], "headers": { "Content-Type": "application/json", "Authorization": "Bearer token" } } """.data(using: .utf8)! let decoder = JSONDecoder() do { let response = try decoder.decode(ServerResponse.self, from: testData) print(response) } catch { print(error) }
补充说明
如果headers的值不只是字符串,你需要自定义一个可解码任意类型的容器(比如用枚举JSONValue包裹不同类型),但按照你原代码的编码逻辑,这里默认headers的键值都可转换为字符串类型。解码时用decodeIfPresent而非decode,可以兼容字段不存在的情况,更符合可选属性的定义。
内容的提问来源于stack exchange,提问作者Maysam
相关产品推荐
相关产品推荐

