17

I'm trying to display a long list of images with titles using the new AsyncImage in SwiftUI. I noticed that when I put VStack around AsyncImage and scroll through images it's reloading images every time I scroll up or down. When there's no VStack I see no reloading and images seem to stay cached.

Is there a way to make VStack not to reload images on scrolling so I can add text under each image?

Here's a working example. Try scrolling with and without VStack.

import SwiftUI

struct TestView: View {

    let url = URL(string: "https://picsum.photos/200/300")

    let columns: [GridItem] = [.init(.fixed(110)),.init(.fixed(110)),.init(.fixed(110))]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(0..<20) { _ in
                    // VStack here causes to images to reload on scrolling
                    VStack {
                        AsyncImage(url: url) { image in
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                        } placeholder: {
                            Image(systemName: "photo")
                                .imageScale(.large)
                                .frame(width: 110, height: 110)
                        }
                    }
                }
            }
        }
    }
}
3
  • 1
    What a bug with pretty basic layout! I think this makes AsyncImage not usable, it's strange that it wasn't reported earlier and fixed before release. Report it to Feedback Assistant and consider switching to this AsyncImage: it's pretty stable Commented Oct 1, 2021 at 8:37
  • Unfortunately, AsyncImage does not cache the images. so each time it downloading an image on the reused cell. Commented Oct 2, 2021 at 11:29
  • 1
    I am using SDWebImage, still I have this issue. Anyone knows how to solve this? Commented Oct 24, 2022 at 9:17

1 Answer 1

12
+200

I fully agree with you that this is a weird bug. I would guess that the reason it's happening has something to do with the way LazyVGrid chooses to layout views, and that using a VStack here gives it the impression there is more than one view to show. This is a poor job on Apple's part, but this is how I solved it: just put the VStacks internal to the AsyncImage. I'm not entirely sure what the original error is, but I do know that this fixes it.

struct MyTestView: View {
    let url = URL(string: "https://picsum.photos/200/300")
    let columns: [GridItem] = [.init(.fixed(110)),.init(.fixed(110)),.init(.fixed(110))]

    var body: some View {
        ScrollView {
            LazyVGrid(columns: columns) {
                ForEach(0..<20) { i in
                    AsyncImage(url: url) { image in
                        VStack {
                            image
                                .resizable()
                                .aspectRatio(contentMode: .fit)
                            
                            Text("label \(i)")
                        }
                    } placeholder: {
                        VStack {
                            Image(systemName: "photo")
                                .imageScale(.large)
                                .frame(width: 110, height: 110)
                            
                            Text("image broken")
                        }
                    }
                }
            }
        }
    }
}
Sign up to request clarification or add additional context in comments.

3 Comments

Heads up that this doesn't seem to work anymore in iOS 16 and corresponding Xcode, Swift/UI versions.
is there any new solution for this. it is not working unfortunately.
Use image.image?.resizable().aspectRatio(contentMode: .fit) instead of image.resizable().aspectRatio(contentMode: .fit)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.