You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 06:22:30