【问题标题】:Mapping arrays in Firestore documents to Swift structs in a SwiftUI app将 Firestore 文档中的数组映射到 SwiftUI 应用程序中的 Swift 结构
【发布时间】:2021-01-10 23:25:02
【问题描述】:

我设法从 Firestore 中获取了数组数据,但是正如您在我遍历 orderDetails 时从图像中看到的那样,详细信息会重复三次,而不是显示三个详细信息!

能否请您检查一下并帮助我知道它有什么问题?

由于我是 SwiftUI 新手,请耐心等待 :)

这是结构:

import SwiftUI
import FirebaseFirestoreSwift
import Firebase

struct OrderDetailsStruct: Identifiable, Codable {
    @DocumentID var id: String?
    var prodName: String
      var prodPic: String
      var prodPrice: String
      var prodQuantity: Int
    
   
}

struct OrderData: Identifiable, Codable {
  @DocumentID  var id: String?
    var orderStatus: String
      var timeStamp: Date
      var orderDetails: [OrderDetailsStruct]?
    
}

这是视图模型:

class OrderDataModel : ObservableObject{
    @Published var userID = "malbagshi@gmail.com"
    @Published var orderData = [OrderData]()
    
    private var db = Firestore.firestore()
    
    func fetchData() {
        
        
        db.collection("orders2/users/\(self.userID)").addSnapshotListener { (querySnapshot, error) in
            guard let documents = querySnapshot?.documents else {
                print("No documents")
                return
            }
            
            self.orderData = documents.compactMap { queryDocumentSnapshot -> OrderData? in
                return try? queryDocumentSnapshot.data(as: OrderData.self)
                
            }
        }
    }
    
}

这里是订单数据视图:

struct OrdersListView: View {
    
     var formatter: DateFormatter = {
        let formatter = DateFormatter()
        formatter.dateFormat = "DD/M MM/YYYY"
        return formatter
    }()
    
    @Environment(\.presentationMode) var present
   // @ObservedObject var orderdetails = getOrderData()
    @StateObject var orderData = OrderDataModel()
    var body: some View {
        
        VStack(alignment: .trailing) {
            HStack(spacing: 20){
                
                Button(action: {present.wrappedValue.dismiss()}) {
                    
                    Image(systemName: "chevron.left")
                        .font(.system(size: 20, weight: .heavy))
                    //.foregroundColor(Color("pink"))
                }
                Spacer()
                Text("My orders")
                    .font(.system(size: 25))
                    //.fontWeight(.heavy)
                    .foregroundColor(.black)
                
                Spacer()
            }
            .padding()
            List{
                ForEach(self.orderData.orderData) {i  in
                    NavigationLink(
                        destination: OrderDetailsView(orderID: i.id!),
                        label: {
                            VStack(alignment: .leading){
                                Text("Order Id: \(i.id!)")
                                .font(.system(size : 13))
                                
                                Text("Order Date: \(self.formatter.string(from: i.timeStamp) )")
                                .font(.system(size: 13))
                                
                                
                                Text("Order Status: \(i.orderStatus)")
                                    .font(.system(size: 13))
                           
                            }
                        })
                    
                }
            }.environment(\.layoutDirection, .rightToLeft)
        }.onAppear{
            orderData.fetchData()
        }
        .navigationBarHidden(true)
        .navigationBarBackButtonHidden(true)
            
       
        
    }
    
   
}

这里是订单详情视图:

import SDWebImageSwiftUI

struct OrderDetailsView: View {
   
    
    @StateObject var orderData = OrderDataModel()
    @State var orderID : String
    
    var body: some View {
         
        VStack(alignment: .leading) {
            ScrollView {
                        ForEach(orderData.orderData) { details in
                           
                                    ForEach((details.orderDetails)!) { orderdetails in
                                        if self.orderID == orderdetails.id {
                                            HStack{
                                               
                                        AnimatedImage(url: URL(string: orderdetails.prodPic))
                                            .resizable()
                                            .aspectRatio(contentMode: .fit)
                                            .frame(width: 50, height: 50)
                                            .background(Color(#colorLiteral(red: 0.921431005, green: 0.9214526415, blue: 0.9214410186, alpha: 1)))
                                            .cornerRadius(10)
                                                
                                                VStack(alignment: .leading){
                                       
                                            Text("Product Name: \(orderdetails.prodName)")
                                                .font(.system(size : 13))
                                        Text("Price: \(orderdetails.prodPrice)")
                                            .font(.system(size : 13))
                                        Text("Quantity: \(orderdetails.prodQuantity)")
                                            .font(.system(size : 13))
                                                }
                                            }
                                        }
                                    }
                              
                        }
                        .padding(.leading, -10.0)
                    }
                   
            
            .onAppear{
                orderData.fetchData()
        }
        }
        
    }
}

enter image description here

【问题讨论】:

  • 你想如何显示/阅读它们?
  • DateFormatter 应该是Date
  • 我需要将它们显示为“订单”列表,然后每个订单都有一个显示“订单详细信息”的新视图列表

标签: swift firebase google-cloud-firestore swiftui


【解决方案1】:

当您使用 Firestore 的 Codable 支持时,映射 Firestore 数据会容易得多。

有关基础知识,请阅读我的文章SwiftUI: Mapping Firestore Documents using Swift Codable - Application Architecture for SwiftUI & Firebase

要处理嵌套数据,只需定义另一个结构。

您的代码如下所示:

struct OrderDetails: Codable {
  var prodName: String
  var prodPic: String
  var prodPrice: String
  var prodQuantity: Int
}

struct OrderData: Codable {
  var orderStatus: String
  var timeStamp: Date
  var orderDetails: [OrderDetails]?
}

请注意,我将 orderDetails 数组标记为可选,以防止在您的文档中不存在该属性时映射中断。

这是视图模型:

class OrderDataModel: ObservableObject {
  @Published var userID = "malbagshi@gmail.com"
  @Published var orderData = [OrderData]()
    
  private var db = Firestore.firestore()
    
  func fetchData() {
    db.collection("orders2/users/\(self.userID)").addSnapshotListener { (querySnapshot, error) in
    guard let documents = querySnapshot?.documents else {
      print("No documents")
      return
    }

    self.orderData = documents.compactMap { queryDocumentSnapshot -> OrderData in
      return try? queryDocumentSnapshot.data(as: OrderData.self)
    }
  }
}

(附带说明 - 类名应始终以大写字母开头。)

还有观点:

struct OrderDetailsView: View {
    
  @Environment(\.presentationMode) var present
    
  @StateObject var orderData = OrderDataModel()

  var body: some View {
    VStack(alignment: .trailing) {
      List {
        ForEach(orderData.orderDetails) { details in
          VStack(alignment: .leading){
            Text("\(details.orderStatus)")
            Text("\(details.timeStamp)")
          }
        }
      }
    }
    .onAppear{
      orderData.fetchData()
    }
  }
}

编辑:查看 Mohammed 的代码后,发现在列表中看到重复条目的实际问题是订单详细信息上的文档 ID 不是唯一的。由于List 要求所有项目都是唯一的,因此此问题会导致无法预测的行为。最好的解决方案是确保文档 ID 是唯一的。

【讨论】:

  • 这让我更加困惑!我尝试使用您的建议,但我不知道如何从中提取数据。
  • 我更新了我的答案以包括从 Firestore 获取数据的位置。
  • 我更新了我的答案,我收到一个错误:表达式类型不明确,没有更多上下文
  • 哦,抱歉 - 我看到了问题。在您看来,您尝试以序列的形式访问 orderData.orderDetails。但是,orderDataOrderData 的数组,所以你不能这样做。您首先必须遍历 orderData 元素。
  • 我按照您的建议更新了代码,但有一个小问题。请你看一下好吗?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-11-09
  • 2019-06-07
  • 1970-01-01
  • 2020-04-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多