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

Swift 4 JSONDecoder解析Codable结构体时keyNotFound错误解决咨询

解决Codable解析时keyNotFound的问题

你遇到的这个问题其实是Swift Codable自动合成逻辑的一个常见坑——虽然你给par1和par2设置了默认值,但如果不做额外处理,自动生成的解码器还是会尝试从JSON中查找对应的键,找不到就抛出keyNotFound错误。下面给你几种实用的解决方案,按需选择:

方案一:自定义CodingKeys,忽略不需要解码的字段

如果par1和par2永远不会从JSON中获取值,只需要保持默认值,那可以定义一个只包含JSON中实际存在字段的CodingKeys枚举,然后手动实现解码初始化方法:

public struct VIO: Codable {
    let id: Int?
    // 其他JSON中存在的字段...
    var par1: Bool = false
    var par2: Bool = false
    
    // 只列出JSON里有的键,排除par1、par2
    private enum CodingKeys: String, CodingKey {
        case id
        // 这里添加其他JSON中存在的字段
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        // 解码JSON中存在的字段
        id = try container.decodeIfPresent(Int.self, forKey: .id)
        // 其他字段的解码逻辑...
        
        // par1和par2直接使用默认值,不需要额外处理
    }
}

这种方法的好处是完全切断了解码器对par1/par2的解析尝试,适合这两个属性仅作为本地默认值使用的场景。

方案二:用decodeIfPresent手动处理默认值

如果JSON中可能存在par1/par2字段(有时有,有时没有),可以在自定义解码方法中用decodeIfPresent尝试解码,找不到就用默认值:

public struct VIO: Codable {
    let id: Int?
    // 其他字段...
    var par1: Bool = false
    var par2: Bool = false
    
    // 包含所有需要处理的键,包括par1、par2
    private enum CodingKeys: String, CodingKey {
        case id, par1, par2
        // 其他字段...
    }
    
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decodeIfPresent(Int.self, forKey: .id)
        // 其他字段解码...
        
        // 尝试解码,找不到就用默认值
        par1 = try container.decodeIfPresent(Bool.self, forKey: .par1) ?? false
        par2 = try container.decodeIfPresent(Bool.self, forKey: .par2) ?? false
    }
}

这种方法兼顾了两种情况:JSON有字段时用字段值,没有时用默认值。

方案三:用@propertyWrapper简化默认值处理

如果你的项目中有很多类似需要默认值的属性,可以用属性包装器来统一处理,代码会更简洁:

// 定义一个属性包装器,处理Bool类型的默认false
@propertyWrapper
struct DefaultFalse: Codable {
    var wrappedValue: Bool
    
    init(wrappedValue: Bool) {
        self.wrappedValue = wrappedValue
    }
    
    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        wrappedValue = try container.decodeIfPresent(Bool.self) ?? false
    }
}

// 在结构体中使用
public struct VIO: Codable {
    let id: Int?
    // 其他字段...
    @DefaultFalse var par1: Bool = false
    @DefaultFalse var par2: Bool = false
}

这样不需要自定义init(from decoder:),自动合成的Codable会调用属性包装器的解码逻辑,自动使用默认值。

为什么原来的代码会报错?

这里补充个知识点:Swift 5.1及以后的版本,对于有默认值的存储属性,自动合成的Codable解码器会在找不到对应键时自动使用默认值。但如果你的Swift版本低于5.1,或者属性是let类型(即使有默认值),自动合成的逻辑就不会处理,就会抛出keyNotFound错误。所以如果你的项目还在使用旧版Swift,必须用上面的自定义方法来解决。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:50:40