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
相关产品推荐
相关产品推荐

