Swift调用Google Elevation API时JSON解码返回全nil问题求助
Swift调用Google Elevation API解码后字段全为nil的问题
我在Swift开发中调用Google Elevation API获取高程数据,写了包含请求发送和JSON响应解码的代码,但遇到了解码后所有字段都为nil的问题。之前我没使用JSONDecoder,尝试把响应数据转成数组处理,但数组元素顺序混乱,不好管理。
我的代码如下:
struct Jresponse: Decodable{ //var results: [Any] var resolution: Int? var elevation: Int? var location: Int? var lat: Int? var lng: Int? } guard let url = URL(string: "https://maps.googleapis.com/maps/api/elevation/json?&locations=\(finalStringConvertedCoordinates)&key=\(apiKey)") else { print("Error: cannot create URL") return } // Create the url request var request = URLRequest(url: url) request.httpMethod = "GET" URLSession.shared.dataTask(with: request) { data, response, error in guard error == nil else { print("Error: error calling GET") print(error!) return } guard let data = data else { print("Error: Did not receive data") return } guard let response = response as? HTTPURLResponse, (200 ..< 299) ~= response.statusCode else { print("Error: HTTP request failed") return } do { guard let jsonObject = try JSONSerialization.jsonObject(with: data) as? [String: Any] else { print("Error: Cannot convert data to JSON object") return } guard let prettyJsonData = try? JSONSerialization.data(withJSONObject: jsonObject, options: []) else { print("Error: Cannot convert JSON object to Pretty JSON data") return } guard let prettyPrintedJson = String(data: prettyJsonData, encoding: .utf8) else { print("Error: Could print JSON in String") return } //print(prettyPrintedJson) jsonResponse = prettyPrintedJson } catch { print("Error: Trying to convert JSON data to string") return } let decoder = JSONDecoder() let jrData = jsonResponse.data(using: .utf8) let jsonResponseProcessed = try! decoder.decode(Jresponse.self, from: jrData! ) print(jsonResponseProcessed) }.resume()
API返回的响应示例(部分):
{ "results" : [ { "elevation" : 11.59268283843994, "location" : { "lat" : 37.78533554077148, "lng" : -122.4059982299805 }, "resolution" : 0.5964969992637634 }, ... ], "status" : "OK" }
解码后打印结果是Jresponse(resolution: nil, elevation: nil, location: nil, lat: nil, lng: nil),所有字段都为nil,求解决办法。
问题根源与解决方案
1. 结构体完全不匹配API响应格式
你的Jresponse结构体和Google Elevation API返回的JSON结构完全不符:
- API最外层是包含
results数组和status字段的对象 results里的每个元素才是包含elevation、location、resolution的对象location是一个包含lat和lng的子对象- 所有数值都是Double类型,不是你定义的Int
你需要重新定义匹配的结构体:
// 匹配location子对象 struct ElevationLocation: Decodable { let lat: Double let lng: Double } // 匹配results数组中的单个元素 struct ElevationResult: Decodable { let elevation: Double let location: ElevationLocation let resolution: Double } // 匹配最外层的API响应 struct ElevationResponse: Decodable { let results: [ElevationResult] let status: String }
2. 多余的JSON转字符串再转Data的流程
你现在的代码把原始data先转成JSON对象,再转成美化的字符串,最后又把字符串转回Data来解码——这完全是多余的操作,不仅浪费性能,还可能引入编码问题。直接用原始的data解码即可。
3. 错误的强制解包(try!和!)
使用try!和强制解包会隐藏错误信息,导致你无法知道解码失败的具体原因。应该用do-catch来捕获解码错误,方便调试。
修改后的完整代码
// 先定义正确的结构体 struct ElevationLocation: Decodable { let lat: Double let lng: Double } struct ElevationResult: Decodable { let elevation: Double let location: ElevationLocation let resolution: Double } struct ElevationResponse: Decodable { let results: [ElevationResult] let status: String } guard let url = URL(string: "https://maps.googleapis.com/maps/api/elevation/json?&locations=\(finalStringConvertedCoordinates)&key=\(apiKey)") else { print("Error: cannot create URL") return } var request = URLRequest(url: url) request.httpMethod = "GET" URLSession.shared.dataTask(with: request) { data, response, error in guard let data = data, error == nil else { print("Error: \(error?.localizedDescription ?? "No data received")") return } guard let httpResponse = response as? HTTPURLResponse, (200..<299).contains(httpResponse.statusCode) else { print("Error: HTTP request failed with status code") return } do { // 直接用原始data解码,不需要转字符串 let elevationResponse = try JSONDecoder().decode(ElevationResponse.self, from: data) print("Decoded successfully!") print("Status: \(elevationResponse.status)") // 遍历所有结果 for result in elevationResponse.results { print("Elevation: \(result.elevation) meters") print("Location: lat \(result.location.lat), lng \(result.location.lng)") print("Resolution: \(result.resolution)\n") } } catch { // 打印解码错误,方便调试 print("Decoding error: \(error)") } }.resume()
调试技巧
如果还是遇到解码问题,可以先打印原始的JSON字符串(不要美化,避免格式问题),然后对比你的结构体字段名和JSON中的键是否完全一致(大小写敏感!):
if let jsonString = String(data: data, encoding: .utf8) { print("Raw JSON: \(jsonString)") }
内容的提问来源于stack exchange,提问作者DESWIJ
相关产品推荐
相关产品推荐

