无法从Weather API获取数据——Swift/JSON开发问题
天气API数据获取失败的问题排查与修复
核心问题分析
- 解码对象错误:weatherapi返回的JSON结构外层是包含
current字段的对象,你直接解码Current类型导致解码失败。 - 错误处理缺失细节:catch块仅打印"failed",无法定位具体错误原因(如解码错误、网络错误)。
- API密钥未替换:URL中的
APIKEY是占位符,必须替换为你在weatherapi.com申请的真实密钥。
修复后的代码
1. WeatherViewModel 修正
class WeatherViewModel: ObservableObject { @Published var tempC: String = "-" @Published var gustMph: String = "-" @Published var errorMessage: String? // 新增错误提示 init() { fetchWeather() } func fetchWeather() { // 替换为你的真实API密钥 guard let url = URL(string: "https://api.weatherapi.com/v1/current.json?key=你的真实API密钥&q=London&aqi=no") else { DispatchQueue.main.async { self.errorMessage = "无效的请求地址" } return } let task = URLSession.shared.dataTask(with: url) { data, response, error in // 处理网络错误 if let error = error { DispatchQueue.main.async { self.errorMessage = "网络请求失败: \(error.localizedDescription)" } return } // 验证HTTP响应状态码 guard let httpResponse = response as? HTTPURLResponse, (200...299).contains(httpResponse.statusCode) else { DispatchQueue.main.async { self.errorMessage = "服务器返回错误状态码" } return } // 处理数据为空的情况 guard let data = data else { DispatchQueue.main.async { self.errorMessage = "未获取到数据" } return } // 解码数据(外层是Weather对象,不是Current) do { let weatherModel = try JSONDecoder().decode(Weather.self, from: data) DispatchQueue.main.async { self.tempC = "\(weatherModel.current.tempC)°C" self.gustMph = "\(weatherModel.current.gustMph) mph" self.errorMessage = nil } } catch { DispatchQueue.main.async { self.errorMessage = "数据解析失败: \(error.localizedDescription)" } print("解码错误详情: \(error)") // 控制台打印详细错误 } } task.resume() } }
2. ContentView 优化(添加错误提示)
struct ContentView: View { @StateObject var viewModel = WeatherViewModel() var body: some View { NavigationView { VStack(spacing: 30) { Text(viewModel.tempC) .font(.system(size: 50)) Text(viewModel.gustMph) .font(.system(size: 30)) // 显示错误信息 if let errorMsg = viewModel.errorMessage { Text(errorMsg) .foregroundColor(.red) .padding(.top, 20) } } .navigationTitle("Weather Test") .padding() } } }
3. 结构体保持不变(原定义符合接口返回结构)
struct Weather: Codable { let current: Current } struct Current: Codable { let tempC: Int let tempF: Double let gustMph: Double let gustKph: Int enum CodingKeys: String, CodingKey { case tempC = "temp_c" case tempF = "temp_f" case gustMph = "gust_mph" case gustKph = "gust_kph" } }
额外注意事项
- 确保API密钥已正确替换,且账户有足够的请求额度。
- 测试设备网络连接,确认能正常访问weatherapi接口。
- 可直接在浏览器中访问请求URL,验证返回的JSON结构是否符合预期。
内容的提问来源于stack exchange,提问作者JohnFromSwindon
相关产品推荐
相关产品推荐

