如何通过JSONDecoder直接从JSON数组获取单个元素的原始Data?
解决方案
要实现直接从数组格式的JSON Data中提取首个元素的原始Data,无需先解码为[A]或修改JSON字符串,可以通过以下方式自定义B的解码逻辑:
核心思路
- 利用
Decoder的无键容器(UnkeyedDecodingContainer)处理数组结构; - 提取数组首个元素的编码内容,通过辅助类型
AnyCodable将其转换为可序列化的JSON对象,最终转回原始Data。
完整代码实现
import Foundation struct B: Codable { let aData: Data init(from decoder: Decoder) throws { // 获取对应数组结构的无键解码容器 var unkeyedContainer = try decoder.unkeyedContainer() // 校验数组非空 guard !unkeyedContainer.isAtEnd else { throw DecodingError.dataCorrupted(.init( codingPath: [], debugDescription: "输入数组为空,无法提取元素" )) } // 获取首个元素的单值解码容器 let singleValueContainer = try unkeyedContainer.singleValueContainer() // 通过AnyCodable解码为任意JSON对象,再转回Data let jsonObject = try singleValueContainer.decode(AnyCodable.self).value aData = try JSONSerialization.data(withJSONObject: jsonObject) } // 可选:实现编码逻辑以满足Codable协议完整性 func encode(to encoder: Encoder) throws { var container = encoder.unkeyedContainer() let jsonObject = try JSONSerialization.jsonObject(with: aData) try container.encode(AnyCodable(jsonObject)) } } // 辅助类型:用于解码/编码任意JSON类型 private struct AnyCodable: Codable { let value: Any init(_ value: Any) { self.value = value } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let int = try? container.decode(Int.self) { value = int } else if let double = try? container.decode(Double.self) { value = double } else if let string = try? container.decode(String.self) { value = string } else if let bool = try? container.decode(Bool.self) { value = bool } else if let array = try? container.decode([AnyCodable].self) { value = array.map { $0.value } } else if let dict = try? container.decode([String: AnyCodable].self) { value = dict.mapValues { $0.value } } else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "无法解码为支持的JSON类型" ) } } func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() switch value { case let int as Int: try container.encode(int) case let double as Double: try container.encode(double) case let string as String: try container.encode(string) case let bool as Bool: try container.encode(bool) case let array as [Any]: try container.encode(array.map(AnyCodable.init)) case let dict as [String: Any]: try container.encode(dict.mapValues(AnyCodable.init)) default: throw EncodingError.invalidValue( value, .init(codingPath: [], debugDescription: "无法编码该类型") ) } } }
使用方式
直接调用JSONDecoder解码数组格式的Data即可:
// 假设arrayData是数组格式的JSON Data if let b = try? JSONDecoder().decode(B.self, from: arrayData) { // b.aData即为数组首个元素的原始JSON Data print(b.aData) }
内容的提问来源于stack exchange,提问作者Jay
相关产品推荐
相关产品推荐

