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

Swift JSON解码提示'id'键缺失但实际存在的解决方法

问题:JSON包含'id'键但解码时提示缺失的原因及解决办法

错误信息

Fatal error: Couldn't parse classification.json as AnimalGroup:
keyNotFound(CodingKeys(stringValue: "id", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"id\", intValue: nil) (\"id\").", underlyingError: nil))

相关代码与JSON样本

AnimalGroup结构体定义

struct AnimalGroup: Identifiable, Decodable, Hashable {
    let id: Int
    let code: Int
    let form: String?
    
    let name: String
    let shortName: String
    
    func hash(into hasher: inout Hasher) {
            hasher.combine(id)
            hasher.combine(name)
        }
}

JSON加载与解码函数

var previewAnimal: Animal = load("animal.json")
var previewGroup: AnimalGroup = load("classification.json")

// Function that loads JSON data into a T type and returns the decoded data
func load<T: Decodable>(_ filename: String) -> T {
    let data: Data

    guard let file = Bundle.main.url(forResource: filename, withExtension: nil)
        else {
            fatalError("Couldn't find \(filename) in main bundle.")
    }

    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }

    do {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase // Remember to add this line to avoid running into a crash
        return try decoder.decode(T.self, from: data)
    } catch {
        fatalError("Couldn't parse \(filename) as \(T.self):\n\(error)")
    }
}

classification.json样本

{
    "group": [
        {
            "code": 3,
            "form": null,
            "id": 1,
            
            "name": "Vertebrates",
            "short_name": "CRS"
        },
        {
            "code": 4,
            "form": null,
            "id": 2,
            
            "name": "Mammal",
            "short_name": "CRS"
        },
        {
            "code": 5,
            "form": null,
            "id": 3,
            
            "name": "Reptile",
            "short_name": "CRS"
        },
        {
            "code": 6,
            "form": null,
            "id": 4,
            
            "name": "Avians",
            "short_name": "CRS"
        },
        {
            "code": 7,
            "form": null,
            "id": 5,
            
            "name": "Amphibians",
            "short_name": "CRS"
        }
    ]
}

原因分析

问题核心是JSON顶层结构与解码目标不匹配:

  • 你的JSON顶层是一个包含group键的对象,group的值才是AnimalGroup类型的数组
  • 但你直接尝试将整个JSON解码为单个AnimalGroup实例,解码器会在JSON顶层寻找id、code等键,自然找不到,因此抛出keyNotFound错误

解决办法

方法1:定义顶层响应结构体(推荐)

新增一个对应JSON顶层结构的结构体,再通过它获取AnimalGroup数组:

struct AnimalGroupResponse: Decodable {
    let group: [AnimalGroup]
}

修改加载代码的类型:

var previewGroup: AnimalGroupResponse = load("classification.json")
// 访问数组:previewGroup.group

方法2:直接解码数组(需调整解码逻辑)

如果不想新增结构体,可以在load函数中先解析顶层对象,提取group数组的数据后再解码:

func loadAnimalGroups(from filename: String) -> [AnimalGroup] {
    let data: Data

    guard let file = Bundle.main.url(forResource: filename, withExtension: nil) else {
        fatalError("Couldn't find \(filename) in main bundle.")
    }

    do {
        data = try Data(contentsOf: file)
    } catch {
        fatalError("Couldn't load \(filename) from main bundle:\n\(error)")
    }

    do {
        let decoder = JSONDecoder()
        decoder.keyDecodingStrategy = .convertFromSnakeCase
        // 先解码为字典提取group数组
        let topLevel = try decoder.decode([String: [AnimalGroup]].self, from: data)
        guard let groups = topLevel["group"] else {
            fatalError("No 'group' key found in \(filename)")
        }
        return groups
    } catch {
        fatalError("Couldn't parse \(filename) as [AnimalGroup]:\n\(error)")
    }
}

// 使用时:
var previewGroup: [AnimalGroup] = loadAnimalGroups(from: "classification.json")

注意:你的shortName与JSON中的short_name对应,已经设置了.convertFromSnakeCase,这部分是正确的,无需修改。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 14:23:12