Reputation: 41
I'm quite a beginner and trying to get the OpenWeather API JSON to show up in my challenge project.
I managed to model it
struct WeatherRespose: Codable {
var weather: [Weather]
var name: String
}
&
import Foundation
struct Weather: Hashable, Codable {
var main: String
var description: String
}
In addition to fetch the data in ContentView. However, when I try to present it:
@State var weatherForcast = Weather()
or @State var weatherForcast = WeatherResponse()
I get this error: Missing argument for parameter 'from' in call, insert 'from: <#Decoder#>'
The only thing that worked for me is to present the data in an array:
@State var weatherForcast = [Weather]()
Any idea what am I missing? thank you so much! Ran
Upvotes: 0
Views: 236
Reputation: 73
I made pretty simple example of how you can do this. There are several additional files, so it's easier to understand how it works in details:
NetworkService
, it will fetch weather data:import Foundation
final class NetworkService{
private let url = "https://example.com"
func performWeatherRequest(completion: @escaping (Result<WeatherResponse, Error>) -> Void){
URLSession.shared.dataTask(with: URL(string: url)!) { data, response, error in
guard let data = data, error == nil else {
completion(.failure(WeatherError.failedToDownload))
return
}
let weatherResponse: WeatherResponse = try! JSONDecoder().decode(WeatherResponse.self, from: data)
completion(.success(weatherResponse))
}.resume()
}
public enum WeatherError: Error {
case failedToDownload
}
}
NetworkService
and prepare to present it in ContentView
import Foundation
import SwiftUI
extension ContentView {
@MainActor class ContentViewVM: ObservableObject {
private var networkService = NetworkService()
@Published var currentWeatherMain: String?
@Published var currentWeatherDescription: String?
func fetchWeather(){
networkService.performWeatherRequest { [weak self] result in
DispatchQueue.main.async {
switch result {
case .success(let weatherResponse):
self?.currentWeatherMain = weatherResponse.weather[0].main
self?.currentWeatherDescription = weatherResponse.weather[0].description
case .failure(_):
print("oops, error occurred")
}
}
}
}
}
}
ContentViewVM
to our ContentView
:import SwiftUI
struct ContentView: View {
@StateObject var viewModel = ContentViewVM()
var body: some View {
VStack {
Text("The main is: \(viewModel.currentWeatherMain ?? "")")
Text("The description is: \(viewModel.currentWeatherDescription ?? "")")
}
.onAppear{
viewModel.fetchWeather()
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Hope it helps.
Upvotes: 1