I'm having trouble getting all images to show in a List using AsyncImage. When you first run the app, it seems fine but if you start scrolling, some Images aren't shown. Either the ProgressView doesn't update until the row is scrolled outside of the screen and back into view or I get an error Code=-999 "cancelled".
I can get the all the images to show and ProgressView to update correctly using a regular Image View and going through the whole setup process of downloading and showing an image. It's only when I try to use AsyncImage that all the images aren't shown. How can I get all AsyncImages to show in a List?
struct ContentView: View {
@StateObject private var viewModel = ListViewModel()
var body: some View {
List {
ForEach(viewModel.images) { photo in
HStack {
AsyncImage(url: URL(string: photo.thumbnailUrl)) { phase in
switch phase {
case .success(let image):
image
case .failure(let error):
let _ = print(error)
Text("error: \(error.localizedDescription)")
case .empty:
ProgressView()
@unknown default:
fatalError()
}
}
VStack(alignment: .leading) {
Text(photo.title)
Text(photo.thumbnailUrl)
}
}
}
}
.task {
await viewModel.loadImages()
}
}
}
@MainActor
class ListViewModel: ObservableObject {
@Published var images: [PhotoObject] = []
func loadImages() async {
do {
let photos = try await AsyncImageManager.downloadImages()
images = photos
} catch {
print("Could load photos: \(error)")
}
}
}
struct AsyncImageManager {
static func downloadImages() async throws -> [PhotoObject] {
let url = URL(string: "https://jsonplaceholder.typicode.com/photos")!
let (data, _) = try await URLSession.shared.data(from: url)
return try JSONDecoder().decode([PhotoObject].self, from: data)
}
}
struct PhotoObject: Identifiable, Codable {
let albumId: Int
let id: Int
let title: String
let url: String
let thumbnailUrl: String
}