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

如何用Swift 4 Codable处理字段值为数组或空字符串的JSON格式不一致问题?

嘿,这种格式不一致的JSON确实挺烦人的,但用Swift的Codable完全能搞定,我来给你分享两个实用的方法!

先假设你的JSON结构大概是这样的:

// 有数据的情况
{
  "data": [{"id": 1}, {"id": 2}]
}

// 无数据的情况
{
  "data": ""
}

方法一:手动实现解码初始化方法

这是最直接的方式,在你的Codable结构体里自定义init(from decoder:)方法,手动处理两种情况:

struct MyResponse: Codable {
    let data: [MyModel]
    
    struct MyModel: Codable {
        let id: Int
    }
    
    enum CodingKeys: String, CodingKey {
        case data
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        
        // 先尝试解码成数组
        if let dataArray = try? container.decode([MyModel].self, forKey: .data) {
            self.data = dataArray
        } else {
            // 如果解码数组失败,尝试解码成字符串(这里我们只关心空字符串的情况)
            let emptyString = try container.decode(String.self, forKey: .data)
            // 不管字符串内容是什么(如果业务允许),都转为空数组
            self.data = []
            // 如果需要严格校验是空字符串,可以加个判断:
            // guard emptyString.isEmpty else {
            //     throw DecodingError.dataCorruptedError(forKey: .data, in: container, debugDescription: "Expected empty string or array")
            // }
        }
    }
}

这种方法的好处是直接把结果统一成数组类型,后续使用的时候不用再处理额外的包装类型,非常省心。如果业务允许,你甚至可以忽略字符串的内容,直接转为空数组;如果需要严格校验是空字符串,就加上注释里的判断逻辑。

方法二:用枚举包装多类型(更灵活)

如果你需要保留“原始值是数组还是空字符串”的信息,或者有多个字段都是这种格式,可以用一个通用的枚举来处理:

// 定义一个通用枚举,支持数组或空字符串
enum ArrayOrEmptyString<T: Codable>: Codable {
    case array([T])
    case emptyString
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        do {
            // 先尝试解码数组
            let array = try container.decode([T].self)
            self = .array(array)
        } catch {
            // 数组解码失败,尝试解码字符串
            let string = try container.decode(String.self)
            guard string.isEmpty else {
                // 如果不是空字符串,抛出错误
                throw DecodingError.dataCorruptedError(in: container, debugDescription: "Expected empty string or array of \(T.self)")
            }
            self = .emptyString
        }
    }
    
    // 如果需要编码回JSON,可以实现这个方法
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .array(let array):
            try container.encode(array)
        case .emptyString:
            try container.encode("")
        }
    }
}

// 在你的响应结构体里使用这个枚举
struct MyResponse: Codable {
    let data: ArrayOrEmptyString<MyModel>
    
    struct MyModel: Codable {
        let id: Int
    }
}

使用的时候,你可以通过switch来处理两种情况:

switch response.data {
case .array(let models):
    print("拿到数组:\(models)")
case .emptyString:
    print("原始值是空字符串")
}

这种方法的优势是通用性强,可以复用在所有类似格式的字段上,而且能保留原始数据的类型信息,适合对数据准确性要求较高的场景。

两种方法都能完美解决你的问题,你可以根据业务需求选择合适的方式~

内容的提问来源于stack exchange,提问作者meaning-matters

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 09:52:23