Swift解码keyNotFound(hours)错误排查及Place结构体优化咨询
Swift解码错误排查与Place结构体简化方案
解码错误(keyNotFound: "hours")排查与解决
出现这个致命错误的核心原因是:解码时找不到hours键,但你的结构体里把它定义成了非可选的必填字段,再加上用了try!强制解包,直接触发崩溃。结合你说数据库已有hours列,具体排查和解决方向如下:
- 先确认实际返回的数据:数据库有列不代表接口/数据源返回的JSON里一定包含
hours键,可能是部分数据行的hours为空导致接口没返回该字段,或者字段名拼写不一致(比如数据库是opening_hours,但接口没映射成hours)。 - 把hours设为可选类型:如果允许Place实例没有营业时间数据,直接修改字段定义为可选,这样解码时缺失键只会赋值为nil,不会报错:
struct Place: Codable { let admission: String let website: String let hours: String? // 改为可选类型 }
- 给非可选字段加默认值:如果hours必须有值,但数据源可能缺失,自定义解码逻辑赋默认值,不用手动处理每个字段:
struct Place: Codable { let admission: String let website: String let hours: String init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) admission = try container.decode(String.self, forKey: .admission) website = try container.decode(String.self, forKey: .website) // 缺失hours时赋默认值 hours = try container.decodeIfPresent(String.self, forKey: .hours) ?? "暂无营业时间" } }
- 替换
try!为安全处理:try!会把所有解码错误直接转为致命错误,改用do-catch或try?避免崩溃:
do { let place = try JSONDecoder().decode(Place.self, from: data) // 处理数据 } catch { print("解码失败:\(error)") }
简化Place结构体写法,避免重复定义CodingKeys
Swift的Codable协议本身支持自动合成CodingKeys,大部分场景下不需要手动写:
- 字段名与键名完全一致时:直接让结构体遵循Codable即可,自动匹配字段和键名,无需任何额外代码:
struct Place: Codable { let admission: String let website: String let hours: String? }
- 字段名与键名不一致时:只需要在CodingKeys里定义不匹配的字段,其余字段自动合成:
struct Place: Codable { let admission: String let website: String let openingHours: String? // 结构体字段名 enum CodingKeys: String, CodingKey { case admission, website case openingHours = "hours" // 仅映射不一致的键 } }
- 批量处理默认值:如果多个字段需要默认值,用@propertyWrapper简化,避免重复写解码逻辑:
@propertyWrapper struct Default<T: Codable> { var wrappedValue: T let defaultValue: T init(defaultValue: T) { self.defaultValue = defaultValue self.wrappedValue = defaultValue } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() wrappedValue = try container.decodeIfPresent(T.self) ?? defaultValue } } extension Default: Encodable where T: Encodable { func encode(to encoder: Encoder) throws { var container = encoder.singleValueContainer() try container.encode(wrappedValue) } } // 使用时直接给字段加注解 struct Place: Codable { let admission: String let website: String @Default(defaultValue: "暂无营业时间") var hours: String }
内容的提问来源于stack exchange,提问作者SLE
相关产品推荐
相关产品推荐

