如何在 SwiftUI 中加载多个图像?

How do I load multiple images in SwiftUI?

目前我有一个从 url 加载图像的图像加载器。但是所有的图像都是一样的。有谁知道我做错了什么?

@State var outfitimage: UIImage?

// .... a lot of lines in between ..... 


        LazyVGrid(columns: columns, spacing: 20) {
            ForEach(data, id: \.id) { item in
                VStack {
                    Text(item.displayname.capitalized)
                        .font(.title3)
                    Image(uiImage: outfitimage!)
                        .resizable()
                        .cornerRadius(15)
                }
                .onAppear{
                    downloadimage(imagename: item.user)
                }

            }
        }


// .... a lot of lines in between ....

func downloadimage(imagename: String) {
    let userimage = "outfits/" + (imagename) + ".jpg"

    Storage.storage().reference().child(userimage).getData(maxSize: 1048576) {
        (imageDataMyOutfit, Error) in
        if let Error = Error {
            print("an error accured: " + Error.localizedDescription)
        } else {
            if let imageDataMyOutfit = imageDataMyOutfit {
                self.outfitimage = UIImage(data: imageDataMyOutfit)
            } else {
                print("couldn't unwrap image data")
            }
        }
    }
}

它使用存储所有图像的 Firebase 存储。我真的不知道我做错了什么。

您只有一个带有 UIImage 的 @State 变量,因此每次从您的 downloadimage 函数加载新图像时,它都会覆盖那个值。

您可以通过几种方式解决此问题:

  1. 使用 imagename 的键(您当前传递给 download image 的值和 UIImage 的值创建一个字典。然后,动态拉动来自那本字典。我还考虑将所有这些移动到 ObservableObject

  2. 使用保持其加载状态的@State 变量将每个图像封装在其自己的子视图中。

第一个版本可能是这样的:

class ImagesLoader : ObservableObject {
    @Published var images : [String:UIImage] = [:]
    
    func downloadImage(imagename: String) {
        let userimage = "outfits/" + (imagename) + ".jpg"
        
        if self.images[imagename] != nil { return }
        
        Storage.storage().reference().child(userimage).getData(maxSize: 1048576) {
            (imageDataMyOutfit, Error) in
            if let Error = Error {
                print("an error accured: " + Error.localizedDescription)
            } else {
                if let imageDataMyOutfit = imageDataMyOutfit, let uiImage = UIImage(data: imageDataMyOutfit) {
                    DispatchQueue.main.async {
                        self.images[imagename] = uiImage
                    }
                } else {
                    print("couldn't unwrap image data")
                }
            }
        }
    }
}


struct ContentView: View {
    @StateObject var imagesLoader = ImagesLoader()
    
    var body: some View {
        LazyVGrid(columns: columns, spacing: 20) {
            ForEach(data, id: \.id) { item in
                VStack {
                    Text(item.displayname.capitalized)
                        .font(.title3)
                    if let uiImage = imagesLoader.images[item.user] {
                        Image(uiImage: uiImage)
                            .resizable()
                            .cornerRadius(15)
                    }
                }
                .onAppear{
                    imagesLoader.downloadImage(imagename: item.user)
                }
            }
        }
    }
}

请注意,除非有图像,否则我不会显示 Image 视图。在您当前的代码中,通过使用 ! 强制展开 UIImage?,如果它曾经是 nil.

,您将导致崩溃

另外值得指出的是,在现实世界的情况下,您可能想要对图像进行更多缓存、错误处理等。您可以研究一个框架来执行此操作,例如 https://github.com/SDWebImage/SDWebImageSwiftUI