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

Swift中用Decodable解析自定义JSON失败,报类型不匹配错误

解决Swift JSON解码错误的方案

首先,我们来拆解你遇到的问题:

错误核心原因

  1. 顶层类型不匹配:你的原始JSON是一个字典({}),但你的代码尝试将它解码成数组([]),这就是错误提示里Expected to decode Array<Any> but found a dictionary instead的由来。
  2. 结构体定义与JSON结构不匹配:你定义的decodeJson和secondLayer的属性名(symbol、exchange)和JSON里的实际键完全对应不上,而且层级结构也搞错了。

正确的解码方案

你的JSON结构可以拆解为:

  • 顶层是一个字典,键为first/second/third等动态字符串
  • 每个顶层键对应的值又是一个字典,键为house/car/ice等动态字符串,值是字符串数组

针对这种动态键的结构,我们可以直接用嵌套字典来解码,不需要额外定义复杂的结构体(当然也可以定义结构体,不过直接用字典更简洁)。

修正后的解码代码

static func decode(jsonString: String) -> [String: [String: [String]]]? {
    let decoder = JSONDecoder()
    guard let jsonData = jsonString.data(using: .utf8) else {
        print("无法将字符串转换为Data")
        return nil
    }
    do {
        // 直接解码为嵌套字典:顶层键 -> 次级键 -> 字符串数组
        let decodedData = try decoder.decode([String: [String: [String]]].self, from: jsonData)
        return decodedData
    } catch {
        print("解码错误:\(error.localizedDescription)")
        print("详细错误信息:\(error)")
        return nil
    }
}

如果一定要用结构体定义

如果你希望用结构体来明确类型(虽然这里键都是动态的,结构体优势不大),可以这样定义:

// 次级结构:对应house/car等键的容器
struct PropertyContainer: Codable {
    // 因为键是动态的,用[String: [String]]来接收
    var properties: [String: [String]]
    
    // 自定义键解码,直接把所有键值对映射到properties属性
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var props = [String: [String]]()
        for key in container.allKeys {
            let value = try container.decode([String].self, forKey: key)
            props[key.stringValue] = value
        }
        self.properties = props
    }
    
    // 自定义编码(如果需要编码的话)
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        for (key, value) in properties {
            let codingKey = CodingKeys(stringValue: key)!
            try container.encode(value, forKey: codingKey)
        }
    }
    
    // 动态CodingKey实现
    private struct CodingKeys: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }
    }
}

// 顶层结构:对应first/second等键的容器
struct Root: Codable {
    var items: [String: PropertyContainer]
    
    // 同样自定义解码,把顶层动态键映射到items属性
    init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        var itemDict = [String: PropertyContainer]()
        for key in container.allKeys {
            let value = try container.decode(PropertyContainer.self, forKey: key)
            itemDict[key.stringValue] = value
        }
        self.items = itemDict
    }
    
    func encode(to encoder: Encoder) throws {
        var container = encoder.container(keyedBy: CodingKeys.self)
        for (key, value) in items {
            let codingKey = CodingKeys(stringValue: key)!
            try container.encode(value, forKey: codingKey)
        }
    }
    
    private struct CodingKeys: CodingKey {
        let stringValue: String
        init?(stringValue: String) {
            self.stringValue = stringValue
        }
        var intValue: Int? { return nil }
        init?(intValue: Int) { return nil }
    }
}

// 对应的解码函数
static func decodeWithStruct(jsonString: String) -> Root? {
    let decoder = JSONDecoder()
    guard let jsonData = jsonString.data(using: .utf8) else {
        print("无法将字符串转换为Data")
        return nil
    }
    do {
        let decodedData = try decoder.decode(Root.self, from: jsonData)
        return decodedData
    } catch {
        print("解码错误:\(error.localizedDescription)")
        print("详细错误信息:\(error)")
        return nil
    }
}

额外注意事项

  • 不要使用try!和强制解包!,这些会在出错时直接崩溃,应该用guard let或if let处理可选值,用do-catch捕获错误。
  • 结构体的命名遵循Swift规范,应该用大驼峰(比如DecodeJson改为Root,SecondLayer改为PropertyContainer),提高代码可读性。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 06:42:33