AsyncImage not rendering all images in a List and producing error Code =-999 "cancelled"

4k Views Asked by At

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
}

enter image description here

enter image description here

enter image description here

2

There are 2 best solutions below

2
On

This is still a bug in iOS 16. The only solution that I found is to use ScrollView + LazyVStack instead of List.

0
On

Did you try to add ".fixedSize()" on your AsyncImage object? Like this:

AsyncImage(
     url: URL(string: "https://XXXXX.png"),
     content: { image in
           image.resizable()
                .aspectRatio(contentMode: .fit)
                .frame(width: 100, height: 100)
     },
     placeholder: {
            ProgressView()
            .frame(width: 100, height: 100)
})
.fixedSize()