无法在 SwiftUI 按钮视图中从 Cloud Firestore 获取数据

Posted

技术标签:

【中文标题】无法在 SwiftUI 按钮视图中从 Cloud Firestore 获取数据【英文标题】:Cannot fetch data from Cloud Firestore in SwiftUI Button view 【发布时间】: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 文件。 【参考方案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)
      
    
  

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

【讨论】:

以上是关于无法在 SwiftUI 按钮视图中从 Cloud Firestore 获取数据的主要内容,如果未能解决你的问题,请参考以下文章

在 SwiftUI 中从 UIViewController 调用函数

在 SwiftUI 中从 UIViewRepresentable 呈现视图

如何在 SwiftUI 中从减去的子视图中关闭视图

如何在swiftUI的父视图中从另一个视图访问变量?

在 SwiftUI 中从数据模型中搜索数组

在 SwiftUI 中从 Observable 视图模型初始化 Map