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)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.