json file : https://dl.dropboxusercontent.com/s/ypknurke7e3062x/swiftuasyncimage.json?dl=0
ContentView.swift
// // ContentView.swift // swiftuidev15ios // // Created by Cairocoders // import SwiftUI struct ContentView: View { @ObservedObject var vmodel = ViewModel() var body: some View { NavigationView { ScrollView { if vmodel.isFetching { ProgressView() } VStack { ForEach(vmodel.courses) { asycimage in let url = URL(string: asycimage.imageUrl) AsyncImage(url: url) { image in image.resizable() .scaledToFill() } placeholder: { ProgressView() } Text(asycimage.name) } } } .navigationTitle("AsyncImage Loading") .task { await vmodel.fetchData() } .navigationBarItems(trailing: refreshButton) } } private var refreshButton: some View { Button { Task.init { vmodel.courses.removeAll() await vmodel.fetchData() } } label: { Text("Refresh") } } } struct ContentView_Previews: PreviewProvider { static var previews: some View { ContentView() } }ViewModel.swift
// // ViewModel.swift // swiftuidev15ios // // Created by Cairocoders // import SwiftUI class ViewModel: ObservableObject { @Published var isFetching = false @Published var courses = [Course]() @Published var errorMessage = "" @MainActor func fetchData() async { let urlString = "https://dl.dropboxusercontent.com/s/ypknurke7e3062x/swiftuasyncimage.json?dl=0" guard let url = URL(string: urlString) else { return } do { isFetching = true let (data, response) = try await URLSession.shared.data(from: url) if let resp = response as? HTTPURLResponse, resp.statusCode >= 300 { self.errorMessage = "Failed to hit endpoint with bad status code" } self.courses = try JSONDecoder().decode([Course].self, from: data) isFetching = false } catch { isFetching = false print("Failed to reach endpoint: \(error)") } } } struct Course: Decodable, Identifiable { let id: Int let name, link, imageUrl: String }