You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Firebase Storage图片URL绑定到SwiftUI的AsyncImage?

从Firebase Storage获取图片并在SwiftUI AsyncImage中显示的问题

我无法通过上传图片时存储下载URL的常规方式实现需求,需要从Firestore读取数据后,再从Firebase Storage获取图片并显示在SwiftUI的AsyncImage中。现有代码能从Firestore拿到数据,但在获取Storage图片URL时遇到问题。

现有数据获取代码

class getData : ObservableObject {
    
    @Published var datas = [dataType]()
    
    init() {
        
        let db = Firestore.firestore()
        
        db.collection("items").getDocuments { (snap, err) in
            
            if err != nil {
                
                print((err?.localizedDescription)!)
                return
            }
            
            for i in snap!.documents {
                
                let id = i.documentID
                let title = i.get("title") as! String
                let description = i.get("description") as! String
                let pic = i.get("pic") as! String
                
                self.datas.append(dataType(id: id, title: title, description: description, pic: pic))
            }
        }
    }
}


struct dataType : Identifiable {
     
    var id = UUID().uuidString
    var title : String
    var description : String
    var pic : String
}

尝试获取图片URL时的错误

我尝试在getData中添加获取Storage下载URL的代码:

let storage = Storage.storage()
let storageRef = storage.reference()
let spaceRef = storageRef.child("itemImages/\(pic)")

spaceRef.downloadURL { url, error in
    if let error = error {
        print("Failed to download url:", error)
        return
    } else {
        print(url!)
    }
}

得到的错误信息显示路径重复,找不到对象:

Failed to download url: Error Domain=FIRStorageErrorDomain Code=-13010 "Object itemImages/itemImages/FD80E18F-C2C0-4E9F-BE8A-7A6AADAC31A3.jpg does not exist." UserInfo={object=itemImages/itemImages/FD80E18F-C2C0-4E9F-BE8A-7A6AADAC31A3.jpg, ResponseBody={
  "error": {
    "code": 404,
    "message": "Not Found."
  }
}, bucket=somee-letters-and-numbers.com, data={length = 65, bytes = 0x7b0a2020 22657272 6f72223a 207b0a20 ... 2e220a20 207d0a7d }, data_content_type=application/json; charset=UTF-8, NSLocalizedDescription=Object itemImages/itemImages/FD80E18F-C2C0-4E9F-BE8A-7A6AADAC31A3.jpg does not exist., ResponseErrorDomain=com.google.HTTPStatus, ResponseErrorCode=404}

解决方案

1. 修复路径重复问题

错误里的路径itemImages/itemImages/xxx说明:Firestore中存储的pic字段本身已经包含了itemImages/前缀。因此代码中不需要再拼接这个前缀,直接使用pic字段的值作为Storage路径即可。

2. 优化数据模型与异步处理

由于获取下载URL是异步操作,需要调整代码逻辑确保UI线程安全更新数据,同时避免强制解包导致崩溃:

修改数据模型

struct dataType : Identifiable {
    var id: String // 直接使用Firestore的documentID,避免UUID重复
    var title : String
    var description : String
    var picURL: URL? // 改为可选URL类型,适配加载失败场景
}

更新数据获取类

class getData : ObservableObject {
    
    @Published var datas = [dataType]()
    
    init() {
        let db = Firestore.firestore()
        
        db.collection("items").getDocuments { [weak self] (snap, err) in
            guard let self = self,
                  let documents = snap?.documents,
                  err == nil else {
                print(err?.localizedDescription ?? "获取Firestore文档失败")
                return
            }
            
            for doc in documents {
                let id = doc.documentID
                guard let title = doc.get("title") as? String,
                      let description = doc.get("description") as? String,
                      let picPath = doc.get("pic") as? String else {
                    print("文档字段解析失败,跳过该条目")
                    continue
                }
                
                // 直接使用Firestore中存储的路径获取Storage引用
                let storageRef = Storage.storage().reference().child(picPath)
                storageRef.downloadURL { url, error in
                    DispatchQueue.main.async { // 必须在主队列更新UI相关数据
                        if let error = error {
                            print("获取图片下载URL失败: \(error.localizedDescription)")
                            // 添加加载失败的条目(可设置默认图片URL)
                            self.datas.append(dataType(id: id, title: title, description: description, picURL: nil))
                            return
                        }
                        
                        self.datas.append(dataType(id: id, title: title, description: description, picURL: url))
                    }
                }
            }
        }
    }
}

3. 在SwiftUI视图中使用AsyncImage

struct ItemListView: View {
    @StateObject private var dataFetcher = getData()
    
    var body: some View {
        List(dataFetcher.datas) { item in
            VStack(alignment: .leading, spacing: 8) {
                Text(item.title)
                    .font(.headline)
                Text(item.description)
                    .font(.subheadline)
                    .foregroundColor(.secondary)
                
                if let picURL = item.picURL {
                    AsyncImage(url: picURL) { phase in
                        switch phase {
                        case .empty:
                            ProgressView() // 加载中占位
                        case .success(let image):
                            image.resizable()
                                .scaledToFit()
                                .cornerRadius(8)
                        case .failure:
                            Image(systemName: "photo.fill") // 加载失败占位
                                .foregroundColor(.gray)
                                .font(.largeTitle)
                        @unknown default:
                            EmptyView()
                        }
                    }
                    .frame(height: 200)
                } else {
                    Image(systemName: "photo.fill")
                        .foregroundColor(.gray)
                        .font(.largeTitle)
                        .frame(height: 200)
                }
            }
            .padding(.vertical, 8)
        }
    }
}

关键说明

  • 路径问题:确认Firestore中pic字段存储的是Storage中图片的完整相对路径(如itemImages/xxx.jpg),不要在代码中重复拼接前缀。
  • 异步安全:downloadURL是异步操作,必须切换到主队列更新@Published数组,否则会导致UI更新异常。
  • 容错处理:使用可选类型和guard let避免强制解包崩溃,同时为加载失败场景提供占位图。

内容的提问来源于stack exchange,提问作者John Smith

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.16 04:20:26