如何重写JSONDecoder方法解析后端返回的自定义非标准Location JSON
解析非标准JSON中的Location字段方案
遇到这种后端返回的非标准JSON确实头疼——标准JSON根本不支持(x, y)这种元组格式,所以默认的JSONDecoder直接罢工很正常。要解决这个问题,我们只需要给Location结构体自定义解码逻辑就行,下面是具体的实现方案:
核心思路
因为(54.000000, 21.000000)不符合JSON规范,所以我们不能直接让解码器把它当成一个对象解析,而是先把它当作字符串读取,再手动处理成我们需要的经纬度数值。
自定义解码的实现代码
修改你的Location结构体,添加自定义的init(from:)方法,同时可以按需添加编码逻辑(如果需要把对象转回后端要求的非标准格式的话):
struct Location: Codable { var latitude: Double var longitude: Double // 自定义解码逻辑 init(from decoder: Decoder) throws { let container = try decoder.container(keyedBy: CodingKeys.self) // 先把location字段按字符串取出 let locationString = try container.decode(String.self, forKey: .location) // 清理字符串:去掉前后的括号,按逗号分割并去除空格 let cleanedString = locationString.trimmingCharacters(in: CharacterSet(charactersIn: "()")) let coordinateComponents = cleanedString.split(separator: ",") .map { $0.trimmingCharacters(in: .whitespaces) } // 验证格式是否合法 guard coordinateComponents.count == 2, let lat = Double(coordinateComponents[0]), let lon = Double(coordinateComponents[1]) else { throw DecodingError.dataCorruptedError( forKey: .location, in: container, debugDescription: "Location格式不符合预期,无法解析为经纬度" ) } latitude = lat longitude = lon } // 可选:如果需要将Location转回后端要求的非标准格式,添加自定义编码 func encode(to encoder: Encoder) throws { var container = encoder.container(keyedBy: CodingKeys.self) let locationString = "(\(latitude), \(longitude))" try container.encode(locationString, forKey: .location) } // 定义编码键 enum CodingKeys: String, CodingKey { case location } }
测试解码效果
用你原来的测试代码试试,现在应该能正常解析了:
let json = """ { "location": (54.000000, 21.000000) } """ let dataJson = json.data(using: .utf8)! do { let location = try JSONDecoder().decode(Location.self, from: dataJson) print("解析成功:纬度\(location.latitude),经度\(location.longitude)") } catch { print("解码失败:\(error)") }
备选方案:预处理JSON字符串
如果你的JSON结构很简单,也可以先把字符串里的(替换成",)替换成",让(x,y)变成"x,y",不过这种方法风险较高——如果JSON里其他地方也有括号(比如字符串内容里),就会破坏原有结构,所以更推荐上面的自定义解码方案。
内容的提问来源于stack exchange,提问作者Ramis
相关产品推荐
相关产品推荐

