我正在嘗試更新我的 viewModel 中的資料,這是我的 viewModel;
import SwiftUI
import CoreLocation
final class LocationViewViewModel: ObservableObject {
static let previewWeather: Response = load("Weather.json")
let weatherManager = WeatherManager()
let locationManager = LocationManager.shared
@Published var weather: Response
init(weather: Response) { // Remove async
DispatchQueue.main.async { // Here, you enter in an async environment
let data = await fetchData() // Read the data and pass it to a constant
DispatchQueue.main.async { // Get on the main thread
self.weather = data // Here, change the state of you app
}
}
}
func fetchData() async -> Response {
guard let weather = try? await weatherManager.getWeather(latitude: weatherManager.latitude!, longitude: weatherManager.latitude!) else { fatalError("Network Error.") }
return weather
}
var city: String {
return locationManager.getCityName()
}
var date: String {
return dateFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(weather.current.dt)))
}
var weatherIcon: String {
if weather.current.weather.count > 0 {
return weather.current.weather[0].icon
}
return "sun.max"
}
var temperature: String {
return getTempFor(temp: weather.current.temp)
}
var condition: String {
if weather.current.weather.count > 0 {
return weather.current.weather[0].main
}
return ""
}
var windSpeed: String {
return String(format: "%0.1f", weather.current.wind_speed)
}
var humidity: String {
return String(format: "%d%%", weather.current.humidity)
}
var rainChances: String {
return String(format: "%0.0f%%", weather.current.dew_point)
}
var dateFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateStyle = .medium
return formatter
}()
var dayFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "EEE"
return formatter
}()
var timeFormatter: DateFormatter = {
let formatter = DateFormatter()
formatter.dateFormat = "hh a"
return formatter
}()
func getTimeFor(time: Int) -> String {
return timeFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(time)))
}
func getTempFor(temp: Double) -> String {
return String(format: "%0.1f", temp)
}
func getDayFor(day: Int) -> String {
return dayFormatter.string(from: Date(timeIntervalSince1970: TimeInterval(day)))
}
}
我還在我的天氣管理器中為我以前的視圖獲取了該資料,所以我在我的 viewModel 中使用了相同的功能。我的天氣管理器;
final class WeatherManager {
var longitude = LocationManager.shared.location?.coordinate.longitude
var latitude = LocationManager.shared.location?.coordinate.latitude
var units: String = "metric"
func getWeather(latitude: CLLocationDegrees, longitude: CLLocationDegrees) async throws -> Response {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/onecall?lat=\(latitude)&lon=\(longitude)&units=\(units)&exclude=hourly,minutely&appid=\(API.API_KEY)") else { fatalError("Invalid Url.")}
let urlRequest = URLRequest(url: url)
let (data, response) = try await URLSession.shared.data(for: urlRequest)
guard (response as? HTTPURLResponse)?.statusCode == 200 else { fatalError("Error while fetching data") }
let decodedData = try JSONDecoder().decode(Response.self, from: data)
return decodedData
}
}
但我堅持編譯錯誤關于初始化我的天氣也試圖讓我的天氣模型可選,但最后我得到了致命錯誤,上面寫著致命錯誤:在展開可選值時意外發現 nil 如果你這樣做,正確的方法是什么在許多視圖和視圖模型中使用獲取的資料
uj5u.com熱心網友回復:
您init()正在嘗試異步運行并且正在更新@Published屬性。即使您設法避免編譯錯誤,您也無法更新將更改視圖狀態的屬性 ( @Published),除非您在主執行緒上。
我的建議:
@Published var weather = Response() // Initialise this property in some way, the dummy values will be used by the app until you complete fetching the data
init(weather: Response) { // Remove async
Task { // Here, you enter in an async environment
let data = await fetchData() // Read the data and pass it to a constant
DispatchQueue.main.async { // Get on the main thread
self.weather = data // Here, change the state of you app
}
}
}
我希望這行得通,但如果在“但我遇到編譯錯誤......”之后你會顯示你發現什么樣的錯誤會更好。我試著用我最好的猜測來解決上面的問題。
uj5u.com熱心網友回復:
我們不在 SwiftUI 中使用視圖模型物件。您的物件正在做 SwiftUI 自動為我們做的不必要的事情,例如格式化字串(因此標簽會在區域設定更改時自動更新)和管理異步任務(任務在視圖出現和資料更改時啟動,并且如果資料在之前更改時也會取消)請求結束或視圖消失)。嘗試重新架構它以正確使用 SwiftUI 資料視圖,例如
struct WeatherView: View {
let location: Location
@State var weather: Weather?
var body: some View {
Form {
Text(weather.date, format: .dateTime) // new simpler formatting
Text(weather.date, formatter: dateFormatter) // label is auto updated when locale changes
Text(weather?.date == nil ? "No date" : "\(weather.date!, format: .dateTime)") // optional handling
}
.task(id: location) { newLocation // tasks auto cancelled and restarted when location changes
weather = await WeatherManager.shared.getWeather(location: newLocation)
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/429698.html
