【问题标题】:Cannot fetch data from Cloud Firestore in SwiftUI Button view无法在 SwiftUI 按钮视图中从 Cloud Firestore 获取数据
【发布时间】:2020-03-30 07:52:59
【问题描述】:

为什么这不起作用? Firestore 中有数据,但似乎该块未执行:

import SwiftUI
import FirebaseFirestore

struct ContentView: View {

    var body: some View {
        VStack{
            Button(
                action: {
                    print("Getting data...")
                    let db = Firestore.firestore().collection("menu")
                    let query = db.order(by: "name", descending: true)
                    query.getDocuments() { snapshot, err in

                        guard let snapshot = snapshot else {
                          return
                        }
                        print(snapshot)
                        for doc in snapshot.documents {
                            print(doc)
                        }
                    }
                },
                label: { Text("Click Me") }
            )
        }
    }
}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

【问题讨论】:

  • 一切都是在堆栈上创建的,所以在退出操作时释放,所以被取消。
  • 我试过你的查询,效果很好。您确定您使用的是正确的密钥吗?比如menuname?
  • 是的,确定一个集合称为菜单,一个字段称为名称。
  • @asperi 你能进一步解释一下吗?该示例来自适用于 Youtube 的教程 - 无法弄清楚我哪里不对。
  • 我很确定 Asperi 没有尝试您的查询。你的menu 收藏下有name 键吗?再次仔细检查,并仔细检查您的项目中是否有正确的 .plist 文件。

标签: ios firebase google-cloud-firestore swiftui


【解决方案1】:

您不应将数据访问逻辑添加到按钮的操作处理程序。相反,将数据访问逻辑提取到视图模型(甚至是存储库)中,然后在视图模型的属性上添加订阅,如下所示:

假设的菜单项数据模型:

struct MenuItem: Identifiable {
  var id: String = UUID().uuidString
  var title: String
}

查看模型:

import Foundation
import FirebaseFirestore

class MenuItemsViewModel: ObservableObject {
  @Published var menuItems = [MenuItem]()

  private var db = Firestore.firestore()

  func fetchData() {
    db.collection("menuitems").addSnapshotListener { (querySnapshot, error) in
      guard let documents = querySnapshot?.documents else {
        print("No documents")
        return
      }

      self.menuItems = documents.map { queryDocumentSnapshot -> MenuItem in
        let data = queryDocumentSnapshot.data()
        let title = data["title"] as? String ?? ""
        return MenuItem(id: .init(), title: title)
      }
    }
  }
}

在你看来:

struct MenuItemsListView: View {
  @ObservedObject var viewModel = MenuItemsViewModel()

  var body: some View {
    NavigationView {
      List(viewModel.menuItems) { menuItem in
        VStack(alignment: .leading) {
          Text(menuItem.title)
            .font(.headline)
        }
      }
      .navigationBarTitle("Menu")
      .onAppear() { // (3)
        self.viewModel.fetchData()
      }
    }
  }
}

使用 Firestore 的 Codable 支持可以进一步简化数据映射:

以下是您需要更新模型的方法:

import FirebaseFirestoreSwift

struct MenuItem: Identifiable, Codable {
  @DocumentID var id: String? = UUID().uuidString
  var title: String  
}

这里是更新的fetchData() 方法:

  func fetchData() {
    db.collection("menuitems").addSnapshotListener { (querySnapshot, error) in
      guard let documents = querySnapshot?.documents else {
        print("No documents")
        return
      }

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

如果这不起作用,请检查日志是否有任何错误消息(例如,您的安全规则可能会阻止您读取数据)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-06-24
    • 2019-10-29
    • 2021-02-24
    • 2019-09-30
    • 2021-09-26
    • 1970-01-01
    • 2021-05-05
    相关资源
    最近更新 更多