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

SwiftUI二手交易App中Firebase图片链接存入Firestore失败问题

SwiftUI Firebase 图片上传后链接无法存入Firestore问题解决

我在开发SwiftUI二手交易App时,尝试将图片上传至Firebase Storage并获取链接存入Firestore,但操作失败——图片链接未能正确关联到对应的商品数据中。

核心代码

上传图片函数uploadPhoto

func uploadPhoto() {
        // Make sure that the selected image poperty isn't nil
        guard selectedImage != nil else{
            return
        }
        let storageRef = Storage.storage().reference()
        //Turn our image into data
        let imageData = selectedImage!.jpegData(compressionQuality: 0.8)
        guard imageData != nil else {
            return
        }
        // Specify the file path an name
        let path = "images/\(UUID().uuidString).jpg"
        let fileRef = storageRef.child(path)
        // Upload that data
        let uploadTask = fileRef.putData(imageData!) { metadata, error in
            if error == nil && metadata != nil {
                fileRef.downloadURL { url, error in
                    guard let url = url, error == nil else {
                        return
                    }
                    let urlString = url.absoluteString
                    print("Download url: \(urlString)")
                    self.imageUrl = urlString
                    let firestoreRef = Firestore.firestore()
                    firestoreRef.collection("users").document().setData(["items": urlString])
                }
            }
        }
    }

添加数据函数addData

// Add data
func addData(items: Items) {
    if let currentUser = currentUser {
        do {
            try db.collection("users").document(currentUser.uid).updateData(["items": FieldValue.arrayUnion([Firestore.Encoder().encode(items)])])
        } catch {
            print("Error occured retriving data")
        }
    }
}

数据模型

struct UserData: Codable, Identifiable {
    @DocumentID var id: String?
    var items: [Items]
}
struct Items: Codable, Identifiable {
    var id = UUID()
    var title: String
    var price: String
    var description: String
    var image: String?
}

触发逻辑

VStack (spacing: 25){
    Button {
        if selectedImage != nil {
            uploadPhoto()
        }
        if title != "" && price != "" && description != ""  {
            viewModel.addData(items: Items(title: title, price: price, description: description, image: imageUrl))
        }
    } label: {
        Text("Publish").font(.buttonTitle)
    }.buttonStyle(CustomButton())
}

问题原因

  1. 异步操作顺序错误:uploadPhoto是异步操作,获取下载URL并赋值imageUrl的逻辑在回调中执行,但按钮点击时addData会立刻触发,此时imageUrl大概率还未被赋值,导致存入Firestore的image字段为空。
  2. Firestore写入逻辑冲突:uploadPhoto中直接创建了新的users文档(firestoreRef.collection("users").document().setData(...)),生成了无关联的无效文档,和addData更新当前用户文档的逻辑矛盾。

解决方案

1. 给uploadPhoto添加完成回调,确保异步流程顺序

修改上传函数,通过闭包返回图片链接,让外部在上传完成后再执行后续操作:

func uploadPhoto(completion: @escaping (String?) -> Void) {
    guard let selectedImage = selectedImage else {
        completion(nil)
        return
    }
    guard let imageData = selectedImage.jpegData(compressionQuality: 0.8) else {
        completion(nil)
        return
    }
    
    let storageRef = Storage.storage().reference()
    let path = "images/\(UUID().uuidString).jpg"
    let fileRef = storageRef.child(path)
    
    fileRef.putData(imageData) { metadata, error in
        guard error == nil, metadata != nil else {
            completion(nil)
            return
        }
        fileRef.downloadURL { url, error in
            guard let url = url, error == nil else {
                completion(nil)
                return
            }
            completion(url.absoluteString)
        }
    }
}

2. 调整按钮触发逻辑,等待上传完成再添加商品

VStack (spacing: 25){
    Button {
        guard title != "", price != "", description != "" else {
            print("请填写完整商品信息")
            return
        }
        
        if let _ = selectedImage {
            viewModel.uploadPhoto { imageUrl in
                guard let imageUrl = imageUrl else {
                    print("图片上传失败")
                    return
                }
                viewModel.addData(items: Items(title: title, price: price, description: description, image: imageUrl))
            }
        } else {
            viewModel.addData(items: Items(title: title, price: price, description: description, image: nil))
        }
    } label: {
        Text("Publish").font(.buttonTitle)
    }.buttonStyle(CustomButton())
}

3. 移除uploadPhoto中无效的Firestore写入代码

删除以下代码,避免生成无关联的用户文档:

let firestoreRef = Firestore.firestore()
firestoreRef.collection("users").document().setData(["items": urlString])

4. 优化addData的错误处理

让错误信息更明确:

func addData(items: Items) {
    guard let currentUser = currentUser else {
        print("未获取到当前用户")
        return
    }
    do {
        let encodedItem = try Firestore.Encoder().encode(items)
        try db.collection("users").document(currentUser.uid).updateData(["items": FieldValue.arrayUnion([encodedItem])])
        print("商品数据添加成功")
    } catch {
        print("添加数据失败: \(error.localizedDescription)")
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 06:05:23