I am trying to update a List using an availableModels array inside an EnvironmentObject. For some reason it doesn't refresh my view but I have no idea why. Very confused about this so help would be much appreciated, I'm new to SwiftUI and transferring data between views. I'm pretty sure that the array is updating because when I print it out the values are correct, but the list doesn't update in the ForEach loop or in the Text fields.
This is my view with the List:
import SwiftUI
var selectedModel: String = "rdps"
struct ModelSelectView: View {
@EnvironmentObject var viewModel: WeatherData
var body: some View {
NavigationView {
List{
Group {
WeatherModelHeader()
}
if !viewModel.weatherArray.isEmpty {
ForEach(viewModel.weatherArray[0].availableModels, id: \.apiName) { model in
WeatherModelCell(weatherModel: model)
}
} else {
Text("No Weather 4 u")
}
Button(action: {
fetchModelInventory(for: viewModel)
}, label: {
Text("Fetch Inventory")
})
Text(String(viewModel.weatherArray[0].availableModels[0].apiName))
Text(String(viewModel.weatherArray[0].availableModels[1].apiName))
Text(String(viewModel.weatherArray[0].availableModels[2].apiName))
Text(String(viewModel.weatherArray[0].availableModels[3].apiName))
}
.navigationTitle("Models")
.onAppear(perform: {
fetchModelInventory(for: viewModel)
print("viewModel.weatherArray.availableModels \(viewModel.weatherArray[0].availableModels)")
})
}
}
}
//Layout for the header of the list
struct WeatherModelHeader: View {
var body: some View {
HStack {
Text("Model \nName")
.bold()
.frame(width: 60, alignment: .leading)
Text("Range")
.bold()
.frame(width: 80, alignment: .leading)
.padding(.leading, 30)
Text("Resolution")
.bold()
.frame(width: 85, alignment: .leading)
.padding(.leading, 30)
}
}
}
//create the layout for the weather model list
struct WeatherModelCell: View {
let weatherModel: WeatherModel
@EnvironmentObject var viewModel: WeatherData
var body: some View {
HStack {
//need to make navlink go to correct graph model. This will be passed in the GraphViews(). Clicking this nav link will trigger the API Call for the coordinates and model.
NavigationLink(
destination: InteractiveChart()
.onAppear{
selectedModel = weatherModel.apiName
fetchData(for: viewModel)
},
label: {
Text(weatherModel.name)
.frame(width: 60, alignment: .leading)
Text("\(String(weatherModel.range)) days")
.frame(width: 80, alignment: .leading)
.padding(.leading, 30)
Text("\(String(weatherModel.resolution)) km")
.frame(width: 80, alignment: .leading)
.padding(.leading, 30)
//this triggers the api call when the model is tapped. it passes the selected model name to the variable selectedModel for the call.
})
}
}
}
And these are my models where I set up my Observable Object:
class WeatherForecastClass: ObservableObject {
//var id = UUID()
var chartMODEL: String = "Model"
var chartModelHeight: Int = 0
var chartLAT: Double = selectedCords.latitude
var chartLON: Double = selectedCords.longitude
var chartDATETIME: Date = formatDate(date: "2023-02-10 18:00")
var chartTMP: Int = 1
var chartRH: Int = 0
var chartDP: Float = 0.0
var chartTTLSnow: Float = 0.0
var chartTTLRain: Float = 0.0
var chartWindSpeed: Int = 0
var chartWindDirDegs: Int = 0
var chartWindDirString: String = ""
var availableModels: [WeatherModel] = weatherModels
}
class WeatherData: ObservableObject {
/// weather data. This is the master class.
@Published var weatherArray: [WeatherForecastClass] = [WeatherForecastClass()]
//@Published var weatherProperties: WeatherForecastClass = WeatherForecastClass()
}
And this is my function for updating the availableModels array:
import Foundation
import SwiftUI
var modelInventory: [String] = []
func fetchModelInventory(for weatherData: WeatherData) {
// @EnvironmentObject var viewModel: WeatherData
let lat = Float(selectedCords.latitude)
let lon = Float(selectedCords.longitude)
let key = "my apiKey"
//this is the url with the API call. it has the data for the call request and my API key.
let urlString = "https://spotwx.io/api.php?key=\(key)&lat=\(lat)&lon=\(lon)&model=inventory"
guard let url = URL(string: urlString) else {
return
}
print(url)
//Gets the data from the api call. tasks are async
let task = URLSession.shared.dataTask(with: url) { data, _, error in
guard let data = data, error == nil else {
print("Error")
return
}
//clear the model inventory
modelInventory = []
weatherData.weatherArray[0].availableModels = []
//decode the modelinventory csv and fill the array
if let csvString = String(data: data, encoding: .utf8) {
let lines = csvString.split(separator: "\n")
for line in lines {
let columns = line.split(separator: ",")
for column in columns {
let value = String(column)
modelInventory.append(value)
}
}
}
print("Model Inventory -----")
print(modelInventory)
if !modelInventory.isEmpty {
DispatchQueue.main.async {
for model in weatherModels {
if modelInventory.contains(model.apiName) {
weatherData.weatherArray[0].availableModels.append(model)
}
}
print(weatherData.weatherArray[0].availableModels)
}
} else {
return
}
}
task.resume()
}
I feel like I've tried everything but I no matter what the list wont update.