SwiftUI中Open-Meteo天气数据无法显示问题求助
问题解决:天气数据无法在SwiftUI界面显示
核心问题总结
你的代码能打印数据但界面不显示,主要是这几个问题:
- 解析后的数据没传递给视图的状态变量
- 视图里用数组存储单个对象,遍历空数组自然没内容
- 网络请求线程没切回主线程,UI更新不生效
- Service和视图之间没有绑定监听
分步修改代码
1. 修复WeatherService(数据获取层)
删掉内部循环引用的代码,添加@Published属性存储数据,并且强制在主线程更新UI:
import Foundation class WeatherService : ObservableObject{ let urlapi = "https://api.open-meteo.com/v1/forecast?latitude=52.40&longitude=13.07&daily=weathercode,temperature_2m_max,temperature_2m_min¤t_weather=true&past_days=1&timezone=Europe%2FBerlin" // 用@Published让视图监听数据变化 @Published var weatherData: WeatherModel? func getDate(){ guard let url = URL(string: urlapi) else { print("URL无效") return } URLSession.shared.dataTask(with: url) { [weak self] data, response, error in guard let data = data, error == nil else{ print("请求出错: \(error?.localizedDescription ?? "未知错误")") return } do { let result = try JSONDecoder().decode(WeatherModel.self, from: data) print(result) // 切回主线程更新UI DispatchQueue.main.async { self?.weatherData = result } } catch { print("解析错误: \(error.localizedDescription)") print(String(describing: error)) } }.resume() } }
2. 修复ContentView(视图层)
改用@StateObject持有Service实例,直接使用单个WeatherModel对象,调整UI显示当前气温和未来7天的高低温:
import SwiftUI struct ContentView: View { // 用StateObject创建Service实例,生命周期和视图绑定 @StateObject private var weatherService = WeatherService() var body: some View { VStack(spacing: 20) { // 显示当前气温 if let currentWeather = weatherService.weatherData?.currentWeather { Text("当前气温: \(currentWeather.temperature)°C") .font(.title) } else { Text("加载中...") } // 显示未来7天的高低温(跳过第一天的历史数据) Text("未来7天预报") .font(.headline) if let dailyData = weatherService.weatherData?.daily { // 从索引1开始,跳过past_days返回的历史数据 ForEach(1..<dailyData.time.count, id: \.self) { index in HStack { Text(dailyData.time[index]) Spacer() Text("最高: \(dailyData.temperature2MMax[index])°C") Spacer() Text("最低: \(dailyData.temperature2MMin[index])°C") } .padding(.horizontal) } } } .onAppear(){ weatherService.getDate() } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }
3. WeatherModel(模型层)
你的模型解析是正常的,不需要修改,如果想优化可以去掉不需要的Identifiable(因为Daily里的数组遍历用索引就够),但当前代码不影响功能:
import Foundation struct WeatherModel: Decodable, Identifiable { var id = UUID() let currentWeather: CurrentWeather let daily: Daily enum CodingKeys: String, CodingKey { case currentWeather = "current_weather" case daily } } struct CurrentWeather: Decodable { let temperature: Double let isDay: Int let time: String enum CodingKeys: String, CodingKey { case temperature case isDay = "is_day" case time } } struct Daily: Decodable { let time: [String] let temperature2MMax, temperature2MMin: [Double] enum CodingKeys: String, CodingKey { case time case temperature2MMax = "temperature_2m_max" case temperature2MMin = "temperature_2m_min" } }
为什么这样改?
@Published+@StateObject让视图能自动监听Service里的数据变化,数据更新时UI自动刷新- 切回主线程是因为SwiftUI只能在主线程更新UI,后台线程的修改不会触发界面刷新
- 接口返回的是单个WeatherModel对象,所以不需要用数组存储,直接用可选类型处理加载状态
- 跳过daily数组的第一个元素,因为你请求了
past_days=1,第一个是历史数据,我们要的是未来7天
内容的提问来源于stack exchange,提问作者user21913599
相关产品推荐
相关产品推荐

