使用Decodable解析JSON时,经纬度变量存在双类型解析问题
解决Decodable解析混合类型经纬度的问题
这问题我之前对接后端API时也踩过坑!这种同一字段返回不同类型的情况确实很棘手,但用Swift的Decodable协议完全能优雅解决,给你两个实用方案:
方案一:自定义可解码的坐标类型(推荐)
我们可以创建一个专门处理Int/String转Double的Coordinate类型,把解码逻辑封装进去,这样主结构体的代码会更清爽:
struct Coordinate: Decodable { let value: Double init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() // 先尝试解析为整数类型(比如无数据时的0) if let intValue = try? container.decode(Int.self) { value = Double(intValue) return } // 失败则尝试解析为字符串,再转成Double let stringValue = try container.decode(String.self) guard let doubleValue = Double(stringValue) else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "无法将坐标字符串「\(stringValue)」转换为Double类型" ) } value = doubleValue } }
然后在你的响应结构体里直接使用这个类型,还可以加计算属性快速获取Double值:
struct LocationResponse: Decodable { let latitude: Coordinate let longitude: Coordinate // 便捷属性,直接拿到经纬度的Double值 var lat: Double { latitude.value } var lon: Double { longitude.value } // 还可以加个判断是否为有效地理数据的属性 var hasValidLocation: Bool { lat != 0.0 && lon != 0.0 } }
方案二:用枚举处理多类型
如果需要保留原始类型的信息(比如区分是Int的0还是字符串的"0"),可以用枚举来实现:
enum CoordinateEnum: Decodable { case integer(Int) case string(String) // 提供转换为Double的便捷属性 var doubleValue: Double? { switch self { case .integer(let int): return Double(int) case .string(let str): return Double(str) } } init(from decoder: Decoder) throws { let container = try decoder.singleValueContainer() if let intVal = try? container.decode(Int.self) { self = .integer(intVal) } else if let strVal = try? container.decode(String.self) { self = .string(strVal) } else { throw DecodingError.dataCorruptedError( in: container, debugDescription: "不支持的坐标类型" ) } } }
使用时在结构体里声明let latitude: CoordinateEnum,之后通过latitude.doubleValue获取数值即可。
这两种方案都能完美解决你遇到的解码错误问题,个人更推荐方案一,因为它直接把类型统一成了Double,后续业务逻辑处理起来更省心。
内容的提问来源于stack exchange,提问作者Nicolai Harbo
相关产品推荐
相关产品推荐

