You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过JSONDecoder直接从JSON数组获取单个元素的原始Data?

解决方案

要实现直接从数组格式的JSON Data中提取首个元素的原始Data,无需先解码为[A]或修改JSON字符串,可以通过以下方式自定义B的解码逻辑:

核心思路

  1. 利用Decoder的无键容器(UnkeyedDecodingContainer)处理数组结构;
  2. 提取数组首个元素的编码内容,通过辅助类型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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:13:33