5

I'm trying to use an AsyncImage to show a ProgressView while it gets an image from a URL, but if it fails to get the image then a different image should be displayed. My code is working in the sense that it will show the different image if the AsyncImage fails to get an image, but I can't get a placeholder ProgressView to show while the async operation is running. The code below does not contain the placeholder modifier and works OK (EDIT: Actually unconfirmed if it's working...):

var body: some View {
    AsyncImage(url: url, scale: scale ?? 1) { phase in
        if let image = phase.image {
            image
                .resizable()
                .aspectRatio(contentMode: contentMode ?? .fit)
                .frame(width: width, height: height)
        } else {
            Image("placeholder_img")
                .resizable()
                .frame(width: 50, height: 50)
                .border(Color(.NeutralPalette5))
                .padding()
                .aspectRatio(contentMode: .fill)
        }
    }
    .frame(width: width, height: height)
}

But adding a placeholder modifier to this code does not work:

var body: some View {
    AsyncImage(url: url, scale: scale ?? 1) { phase in
        if let image = phase.image {
            image
                .resizable()
                .aspectRatio(contentMode: contentMode ?? .fit)
                .frame(width: width, height: height)
        } else {
            Image("placeholder_img")
                .resizable()
                .frame(width: 50, height: 50)
                .border(Color(.NeutralPalette5))
                .padding()
                .aspectRatio(contentMode: .fill)
        }
    } placeholder: {
        ProgressView()
            .progressViewStyle(.circular)
    }
    .frame(width: width, height: height)
}

The above results in the following error:

Failed to produce diagnostic for expression; please submit a bug report (https://swift.org/contributing/#reporting-bugs) and include the project

Can anyone tell me how I can use a placeholder with my code? I'm basically trying to show a ProgressView while the AsyncImage gets the image, but if it fails to get the image then a different image should be displayed, so if there's a better way to do that please let me know.

1 Answer 1

10

When you use AsyncImage(url: ...) with a placeholder: {..} you have the image, not the phase.

 var body: some View {
     AsyncImage(url: url) { image in  // <-- here
         image.resizable()
     } placeholder: {
         ProgressView().progressViewStyle(.circular)
     }
 }

To present a different image, presumably after a certain time has passed, you will have to create the code yourself. Or use the following approach with the phase:

 AsyncImage(url: url) { phase in
     if let image = phase.image {
         image.resizable() // Displays the loaded image.
     } else if phase.error != nil {
         Image("Goofy") // Indicates an error, show default image
     } else {
         // Acts as a placeholder.
         ProgressView().progressViewStyle(.circular)
         // Image("Mickey Mouse")
     }
 }
Sign up to request clarification or add additional context in comments.

Comments

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.