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
}
