I have a weather app that I am creating. I use an API (OpenWeatherApp) to get my data. I load the data into an array, weatherArray
, of type struct WeatherJSON
.
I can successfully access the data using a ForEach
loop, but when I try to directly access specific data using array[index]
, I get the following error: Thread 1: Fatal error: Index out of range
Here is the top-level struct that I am using:
// holds all data from the JSON request
struct WeatherJSON: Codable {
var coord: Coord // coordinate struct
var weather: [Weather] // array of Weather struct
var base: String // "internal parameter..?"
var main: Main // main struct (contains the juicy data)
var visibility: Int // visibility number
var wind: Wind // wind struct
var clouds: Clouds // clouds struct
var dt: Int // time of data calculation, unix, UTC
var sys: Sys // internal parameer
var timezone, id: Int // timezone
var name: String // city namme
var cod: Int // another internal parameter (..?)
}
My ContentView:
struct ContentView: View {
@State private var weatherArray: [WeatherJSON] = []
// @State private var weatherArray: [Weather] = []
var body: some View {
NavigationView {
VStack {
Text("(weatherArray[0].name)") // <---- This doesn't work
List {
// Text("Current conditions: (weatherArray[0].description)")
// ForEach(weatherArray, id: .self) { result in
// Section(header:Text("Address")) {
// Text("Current conditions: (result.main)")
// .font(.headline)
// .bold()
// Text("Weather description: (result.description)")
// .font(.body)
// }
// }
}
.navigationTitle("Weather")
}
}
.task { await handleData() }
}
func handleData() async {
guard let url = URL(string: "https://api.openweathermap.org/data/2.5/weather?q=Seattle&appid={APIKEY}") else {
print("This URL does not work!")
return
}
let decoder = JSONDecoder()
do {
let (weatherData, _) = try await URLSession.shared.data(from: url)
if let weatherObj = try? decoder.decode(WeatherJSON.self, from: weatherData) {
weatherArray.append(weatherObj)// = weatherObj.weather
print(weatherArray[0]) // <--- This works?
}
} catch {
print("Did not work :(")
}
} ```
2
Answers
Your view is accessing the
weatherArray
before the data has been loaded. You need to account for a possibly empty array to avoid the crash.Change:
To:
try this example code to get the weather data into your models and use it in your view: