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

Swift中如何解析Codable结构体的任意类型rowSet属性?

解决Swift Codable中任意类型嵌套数组的解析问题

你的问题在于rowSet是包含任意类型元素的嵌套数组,而Swift的Codable协议不支持直接使用[Any]或[AnyObject]作为解码类型。下面提供两种可行的解决方案:

方案一:自定义枚举处理JSON基本类型

通过定义一个枚举来覆盖JSON中可能出现的基本类型(字符串、整数、浮点数等),让其遵循Codable协议,以此兼容任意类型的元素。

1. 定义JSONValue枚举

enum JSONValue: Codable {
    case string(String)
    case int(Int)
    case double(Double)
    case bool(Bool)
    
    // 解码逻辑:尝试匹配不同的JSON类型
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        
        if let stringVal = try? container.decode(String.self) {
            self = .string(stringVal)
        } else if let intVal = try? container.decode(Int.self) {
            self = .int(intVal)
        } else if let doubleVal = try? container.decode(Double.self) {
            self = .double(doubleVal)
        } else if let boolVal = try? container.decode(Bool.self) {
            self = .bool(boolVal)
        } else {
            throw DecodingError.dataCorruptedError(
                in: container,
                debugDescription: "无法解析为支持的JSON基本类型"
            )
        }
    }
    
    // 编码逻辑:根据枚举类型对应编码
    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .string(let val): try container.encode(val)
        case .int(let val): try container.encode(val)
        case .double(let val): try container.encode(val)
        case .bool(let val): try container.encode(val)
        }
    }
}

2. 修改ResultSet结构体

注意:你的JSON示例中使用的键是resource,但结构体中定义的是name,需要通过CodingKeys修正映射关系,否则会解码失败。

struct ResultSet: Codable {
    var name: String
    var headers: [String]
    var rowSet: [[JSONValue]]
    
    enum CodingKeys: String, CodingKey {
        case name = "resource" // 修正键名映射
        case headers
        case rowSet
    }
}

struct Scoreboard: Codable {
    var resultSets: [ResultSet]
}

使用示例

解码后可以通过switch判断元素类型:

let jsonData = // 你的JSON数据
do {
    let scoreboard = try JSONDecoder().decode(Scoreboard.self, from: jsonData)
    for resultSet in scoreboard.resultSets {
        print("资源名称:\(resultSet.name)")
        for row in resultSet.rowSet {
            for element in row {
                switch element {
                case .string(let str): print("字符串元素:\(str)")
                case .int(let num): print("整数元素:\(num)")
                case .double(let num): print("浮点数元素:\(num)")
                case .bool(let flag): print("布尔元素:\(flag)")
                }
            }
        }
    }
} catch {
    print("解码失败:\(error)")
}

方案二:实现通用AnyCodable类型

如果需要支持更复杂的JSON结构(比如嵌套对象、数组),可以实现一个AnyCodable结构体来容纳任意JSON类型:

1. 定义AnyCodable

struct AnyCodable: Codable {
    let value: Any
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        
        if let val = try? container.decode(String.self) {
            value = val
        } else if let val = try? container.decode(Int.self) {
            value = val
        } else if let val = try? container.decode(Double.self) {
            value = val
        } else if let val = try? container.decode(Bool.self) {
            value = val
        } else if let val = try? container.decode([AnyCodable].self) {
            value = val.map { $0.value }
        } else if let val = try? container.decode([String: AnyCodable].self) {
            value = val.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 val as String: try container.encode(val)
        case let val as Int: try container.encode(val)
        case let val as Double: try container.encode(val)
        case let val as Bool: try container.encode(val)
        case let val as [Any]: try container.encode(val.map(AnyCodable.init))
        case let val as [String: Any]: try container.encode(val.mapValues(AnyCodable.init))
        default:
            throw EncodingError.invalidValue(
                value,
                EncodingError.Context(
                    codingPath: container.codingPath,
                    debugDescription: "无法编码该类型"
                )
            )
        }
    }
}

2. 修改ResultSet结构体

同样需要修正键名映射:

struct ResultSet: Codable {
    var name: String
    var headers: [String]
    var rowSet: [[AnyCodable]]
    
    enum CodingKeys: String, CodingKey {
        case name = "resource"
        case headers
        case rowSet
    }
}

struct Scoreboard: Codable {
    var resultSets: [ResultSet]
}

使用示例

解码后通过value属性获取原始值,并进行类型判断:

do {
    let scoreboard = try JSONDecoder().decode(Scoreboard.self, from: jsonData)
    for resultSet in scoreboard.resultSets {
        for row in resultSet.rowSet {
            for element in row {
                switch element.value {
                case let str as String: print("字符串:\(str)")
                case let num as Int: print("整数:\(num)")
                case let num as Double: print("浮点数:\(num)")
                case let flag as Bool: print("布尔值:\(flag)")
                case let arr as [Any]: print("数组:\(arr)")
                case let dict as [String: Any]: print("字典:\(dict)")
                default: print("未知类型")
                }
            }
        }
    }
} catch {
    print("解码失败:\(error)")
}

内容的提问来源于stack exchange,提问作者Omar Ebrahim

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.02 00:35:31