AsyncImage in a Button or NavigationLink doesn't load while scrolling List

Viewed 131

This used to work fine before but since Xcode 14 if I use an AsyncImage inside a Button or NavigationLink in my list the image loads the first time but when the cell is reused it only displays the placeholder.

Two things I noticed:

  1. clicking on the button immediately fixes the image in that cell
  2. If I remove the Button and add the view with the AsyncImage directly in the ForEach the problem disappears

enter image description here

Code example:

import SwiftUI

struct ContentView: View {
    @StateObject var viewModel = ItemListViewModel()
    
    var body: some View {
        List {
            ForEach(viewModel.items, id: \.self) { item in
                Button {

                } label: {
                    HStack {
                        AsyncImage(url: URL(string: "https://www.appatar.io/com.facebook.Facebook")) { phase in
                            if let image = phase.image  {
                                // SHOW IMAGE
                                image
                                    .resizable()
                                    .frame(width: 40, height: 40)

                            } else if phase.error != nil {
                                // FAILED
                                HStack {
                                    Image(systemName: "exclamationmark.triangle")
                                    Text(phase.error?.localizedDescription ?? "")
                                }
                                .padding()

                            } else {
                                // LOADING
                                Color.red
                                    .frame(width: 40, height: 40)
                            }
                        }

                        Text("Item #\(item)")
                    }
                    .padding()
                }
            }
            
            Section {
                ProgressView()
                    .onAppear {
                        viewModel.retrieveDataFromAPI()
                    }
            }
            .navigationBarTitle("Pagination Test")
        }
    }
}

class ItemListViewModel: ObservableObject {
    @Published var items: [Int] = []
    
    func retrieveDataFromAPI(completion: (() -> Void)? = nil) {
        DispatchQueue.main.asyncAfter(deadline: .now() + 0.3) { [weak self] in
            guard let self = self else { return }
            
            let newData = Array(self.items.count...(self.items.count + 50))
            self.items.append(contentsOf: newData)
            completion?()
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

1 Answers
Related