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

SwiftUI中无法上传含嵌套数组的对象至Firestore求助

SwiftUI上传含数组的Order对象到Firestore失败问题

问题概述

在SwiftUI项目中,尝试将包含字符串数组的Order对象上传至Firestore时失败,已确认构造的Order数据格式正确,但上传时抛出FirestoreEncodingError。

待保存的对象示例:
customer: irelyn - items: ["Chicken Bacon Ranch", "BLT"] - total price: 17.30

错误信息

The operation couldn’t be completed. (FirebaseFirestoreSwift.FirestoreEncodingError error 0.)

相关代码

保存函数

// function to save the order 
func saveItem(item: Order, completion: @escaping (Error?) -> ()) {
    let db = Firestore.firestore()
    let encoder = JSONEncoder()
    do {
        let data = try encoder.encode(item)
        let dictionary = try JSONSerialization.jsonObject(with: data, options: []) as? [String : Any] ?? [:]
        db.collection("items").addDocument(data: dictionary) { (error) in
            completion(error)
        }
    } catch {
        completion(error)
    }
}

数据模型

struct Order: Identifiable, Codable {
    @DocumentID var id: String?
    let customer: String
    let total: String
    let orderItems: [String]
}

// the menuitem objects -> im storing the name into an array for all the items being ordered in the object above 
struct MenuItem: Identifiable, Codable {
    var id: String?
    var name: String
    var description: String
    var price: Double
}

视图下单代码

Button {
    // store the menu items
    let array: [MenuItem] = appVM.myCart
    let menuItems: [String]  = array.map { $0.name }
    
    let formatter = NumberFormatter()
    formatter.minimumFractionDigits = 2
    formatter.maximumFractionDigits = 2
    
    let price = appVM.totalAmount
    let orderTotal = formatter.string(for: price) ?? ""
    let user = loginVM.currentUser?.fullName
    
    // store the new order with total, name, and order
    let newOrder = Order(customer: user ?? "",total: orderTotal, orderItems: menuItems)
    
    print("customer: \(newOrder.customer) - items: \(newOrder.orderItems) - total price: \(newOrder.total)")
    
    appVM.saveItem(item: newOrder) { (error) in
        if let error = error {
            print(error.localizedDescription)
        } else {
            print("Success")
        }
    }
} label: {
    Text("Place My Order!")
        .bold()
        .padding()
        .frame(maxWidth: .infinity)
        .background(Color.white)
        .cornerRadius(30)
        .padding(.horizontal)
        .foregroundColor(.orange)
}

解决方案

问题出在编码方式:系统JSONEncoder无法正确处理Firebase的@DocumentID属性,导致编码失败。需改用FirebaseFirestoreSwift提供的Firestore.Encoder来编码对象。

修改后的保存函数:

func saveItem(item: Order, completion: @escaping (Error?) -> ()) {
    let db = Firestore.firestore()
    let encoder = Firestore.Encoder() // 使用Firestore专用编码器
    do {
        let dictionary = try encoder.encode(item)
        db.collection("items").addDocument(data: dictionary) { error in
            completion(error)
        }
    } catch {
        completion(error)
    }
}

注意事项

  1. 确保项目已导入FirebaseFirestoreSwift框架(通过CocoaPods或Swift Package Manager添加)
  2. Order模型的Codable实现无误,所有属性符合编码要求
  3. 无需通过JSONSerialization二次转换,Firestore.Encoder直接输出Firestore可接受的[String: Any]格式

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 18:05:29