arraysswiftswiftuiswiftui-asyncimage

Store loaded image in swifui Asyncimage to an array


I have one swiftui application in i am loading images from server and displaying it and uaisng AsyncImage. I want to store image in an array. how to store image inside asynview in array

@State private var images: [Image?] = []
var outputImageArray: [String] = ["https://replicate.delivery/pbxt/KJmFdQRQVDXGDVdVXftLvFrrvgOPXXRXbzIVEyExPYYOFPyF/80048a6e6586759dbcb529e74a9042ca.jpeg",
                                  "https://replicate.delivery/pbxt/KIIutO7jIleskKaWebhvurgBUlHR6M6KN7KHaMMWSt4OnVrF/musk_resize.jpeg",
                                  "https://replicate.delivery/pbxt/KI4a4NSCc0sAFMdlbD4n8ufHLXb2utKIwwbQff0M2ryhGJPJ/pp_0.jpg"
]


HStack {
    ForEach(Array(outputImageArray.enumerated()), id: \.element) { index, imageUrl in
        //     ForEach(outputImageArray ?? [], id: \.self) { imageUrl in
        AsyncImage(url: URL(string: imageUrl)) { sourceImage in
            self.images[index] = sourceImage
    
            sourceImage
                .resizable()
                .frame(width: 70, height: 100)   // <--- here
                .aspectRatio(contentMode: .fill)  // <--- here
                .clipped()
                .clipShape(RoundedRectangle(cornerRadius: 10))
                .overlay(RoundedRectangle(cornerRadius: 10).stroke(Color.gray, lineWidth: 1))
            // .blur(radius: takenImageName != selectedImage ? 1 : 0)
                .opacity(selectedImage != imageUrl ? 0.6 : 1.0) // Opacity for unselected images

        } placeholder: {
            ProgressView()
            
        }.onTapGesture {
            // self.mainImageUrl = imageUrl
            self.selectedImage = imageUrl
            self.isDefaultSelected = false
            //  self.takenImageName = imageUrl
            print("taken image name tap",takenImageName)
            print("selectedImage",selectedImage)
        }
    }
}

Getting error : Type '()' cannot conform to 'View' at lineself.images[index] = sourceImage


Solution

  • The error you get is because you cannot have this (normal procedural) code self.images[index] = sourceImage inside the closure.

    Instead use the other version of AsyncImage with phase, such as this example code:

     AsyncImage(url: url: URL(string: imageUrl)) { phase in
         switch phase {
             case .empty: ProgressView()
                 
             case .success(let image):
                 image.resizable()
                    // ....
                     .onAppear {
                         self.images[index] = image
                     }
                 
             case .failure: Image(systemName: "wifi.slash")
             @unknown default: EmptyView()
         }
     }
    

    In fact, you could use your original code with sourceImage, as long as you add and .onAppear {...} to it.