iOS WeatherKit获取逐小时预报为空,请求技术协助
解决WeatherKit获取逐小时预报为空的问题
问题描述
我已经通过以下代码成功获取当前天气状况:
var weatherDescription: String { let description = weather?.currentWeather.condition.description ?? "Loading..." return description }
但尝试获取逐小时预报并打印时,结果为空:
var hourlyWeatherForecast: Forecast<HourWeather> { let forecast = (weather?.hourlyForecast)! //TODO: handle error case print (forecast) return forecast }
我是基础薄弱的业余程序员,恳请帮助!
以下是该类的完整代码:
// // WeatherKitManager.swift // FranzFahrenheitv2 // // Created by Björn Schefzyk on 3/25/23. // import Foundation import WeatherKit @MainActor class WeatherKitManager: ObservableObject { @Published var weather: Weather? func getWeather(latitude: Double, longitude: Double) async { do { weather = try await Task.detached(priority: .userInitiated) { return try await WeatherService.shared.weather(for: .init(latitude: latitude, longitude: longitude)) }.value //print("Weather: \(String(describing: weather))") } catch { fatalError("\(error)") } } var symbol: String { weather?.currentWeather.symbolName ?? "xmark" } var tempC: String { let temp = Int(weather?.currentWeather.temperature.value ?? 0) let convert = String(temp) + "°C" return convert } var tempF: String { let temp = Int(weather?.currentWeather.temperature.converted(to: .fahrenheit).value ?? 0) let convert = String(temp) + "°F" return convert } var weatherDescription: String { let description = weather?.currentWeather.condition.description ?? "Loading..." return description } var hourlyWeatherForecast: Forecast<HourWeather> { let forecast = (weather?.hourlyForecast)! //TODO: handle error case print (forecast) return forecast } }
问题分析与解决步骤
1. 修复强制解包的风险
你当前用!强制解包weather?.hourlyForecast,如果weather未加载完成或获取失败,不仅会崩溃,还可能因解包时机错误拿到空值。先改成安全的可选绑定:
var hourlyWeatherForecast: Forecast<HourWeather>? { guard let forecast = weather?.hourlyForecast else { print("逐小时预报未加载或获取失败") return nil } print(forecast) return forecast }
2. 显式指定WeatherKit请求的预报类型
虽然默认请求会包含逐小时数据,但显式指定可确保获取到目标数据,避免遗漏:
修改getWeather方法:
func getWeather(latitude: Double, longitude: Double) async { do { let weatherService = WeatherService.shared // 明确指定获取当前天气和逐小时预报 let weather = try await weatherService.weather( for: .init(latitude: latitude, longitude: longitude), including: [.current, .hourly] ) self.weather = weather print("完整Weather数据:\(weather)") // 打印完整数据确认是否包含hourlyForecast } catch { print("获取天气失败:\(error)") self.weather = nil // 替换fatalError,避免程序直接崩溃 } }
3. 确保打印时机正确
hourlyWeatherForecast是计算属性,只有被访问时才会执行打印。如果在weather未加载完成时访问,自然拿到空值。要在weather加载完成后再访问它,比如在View中这样使用:
struct ContentView: View { @StateObject private var weatherManager = WeatherKitManager() var body: some View { VStack { if let hourlyForecast = weatherManager.hourlyWeatherForecast { Text("逐小时预报数量:\(hourlyForecast.forecast.count)") // 遍历显示每小时数据 ForEach(hourlyForecast.forecast, id: \.date) { hour in Text("\(hour.date.formatted(.dateTime.hour())): \(hour.temperature.value.formatted())°C") } } else { Text("加载中...") } } .task { await weatherManager.getWeather(latitude: 37.334722, longitude: -122.008889) // 替换为你的目标坐标 } } }
4. 优化Forecast对象的打印方式
直接打印Forecast对象会因为默认描述不够详细,看起来像空值。可以打印其内部的forecast数组查看具体数据:
var hourlyWeatherForecast: Forecast<HourWeather>? { guard let forecast = weather?.hourlyForecast else { print("逐小时预报未加载") return nil } print("逐小时预报数量:\(forecast.forecast.count)") print("第一个小时数据:\(forecast.forecast.first ?? "无数据")") return forecast }
内容的提问来源于stack exchange,提问作者Björn
相关产品推荐
相关产品推荐

