0

我在我的 SwiftUI 应用项目中使用 Firebase Firestore。在应用程序开始时,我想从各种集合中读取多个文档。

假设我有集合 A(1 个文档)、B(2 个文档)和 C(4 个文档)。来自 A 和 B 的文档中的数据决定了必须读取 CI 中的哪些文档。

目前,我有一个 DatabaseHelper 类,它对每个集合都有一个 readCollection 函数(这些 readCollection 函数中的每一个都调用 readDocument 函数来为每个所需的文档创建一个侦听器)。每个 readCollection 函数以及每个 readDocument 函数都有一个完成处理程序。在应用程序启动时,我从阅读集合 A 开始。完成阅读后,它开始阅读 B,依此类推:

func listen(completion: @escaping () -> ()) {
  readA() {
    readB() {
      readC() {
        completion()
      }
    }
  }
}

在显示任何数据之前,我的应用程序正在等待侦听功能完成。

这种方法“有点工作”,但是,它似乎不是最佳方法。例如,如果我读取 A,然后我从 B 读取两个文档,则从 B 调用完成处理程序两次,这导致两次调用 readC(),除非我计算 B 的文档读取并且仅在最后阅读。那么,问题是,只有对 B 中的第二个文档的更新会触发完成处理程序并从 C 重新加载文档,而不是对 B 中的第一个文档的更新。

当然,必须有一个更好的逻辑来在我的应用程序启动时从数据库中加载我的数据,它可以在运行时正确处理每个文档更新,并且没有不必要的重复读取。

有没有人有更好的方法?谢谢

4

1 回答 1

2

所以这是一个可能的解决方案。您必须根据需要对其进行修改,但由于您为您的问题提供的代码很少甚至没有,因此它必须这样做。

  1. 从 A 获取数据
  2. 当该数据到达时,使用它来确定从 B 获取哪些数据。为此使用完成处理程序。其他解决方案可以是但不限于(Dispatcher 等)。
  3. 使用从 B 提供的数据确定从 C 获取什么数据。与 Nr.2 中相同的过程等待它。

这只是您的问题的潜在过程的基本表示。它过于简单,但应该可以帮助您理解:

class DatabaseHelper: ObservableObject {
    
    @Published var myDataA: Array<String> = []
    @Published var myDataB: Array<String> = []
    @Published var myDataC: Array<String> = []
    
    init() {
        self.getData(dataBaseACollectionName: "dataBase_A")
    }
    
    // Get A Data
    private func getData(dataBaseACollectionName: String) {
        self.dataBaseCollectionGetDocuments(collectionName: dataBaseACollectionName) { isSucceededA in
            if !isSucceededA.isEmpty {
                self.myDataA = isSucceededA
                
                // Get first "documentID from A to determine what in B I have to read
                self.getSpecificDocumentFromDataBase(collectionName: self.myDataA.first ?? "randomCollection", documentID: self.myDataA.first ?? "randomDocument") { isSucceededB in
                    if !isSucceededB.isEmpty {
                        self.myDataB = isSucceededB
                        
                        // Get first "documentID from B to determine what in C I have to read
                        self.getSpecificDocumentFromDataBase(collectionName: self.myDataB.first ?? "randomCollection", documentID: self.myDataB.first ?? "randomDocument") { isSucceededC in
                            if !isSucceededC.isEmpty {
                                self.myDataC = isSucceededC
                                // done
                            }
                        } // C
                        
                    }
                } // B
                
            } // A
        }
    }
    
    // I made just one wrapper function for the DB call as all myData Arrays are from the same type (containing Strings)
    private func dataBaseCollectionGetDocuments(collectionName: String ,completing: @escaping (Array<String>) -> Void) {
        
        if !collectionName.isEmpty {
            var dataArray: Array<String> = []
            let group = DispatchGroup()
            group.enter() // initial enter
            
            Firestore.firestore().collection(collectionName).getDocuments() { (documents, error) in
                if error != nil {
                    print("Error getting amount of recipes in last seen")
                } else {
                    for doc in documents!.documents {
                        group.enter()
                        dataArray.append(doc.documentID) // Just appending ID as it is a String
                        group.leave()
                    }
                }
                group.leave() // Initial leave
            }
            
            group.notify(queue: DispatchQueue.global(qos: .background)) {
                completing(dataArray)
            }
        }
        
    }
    
    // For Specific documents
    private func getSpecificDocumentFromDataBase(collectionName: String, documentID: String ,completing: @escaping (Array<String>) -> Void) {
        
        if !collectionName.isEmpty && !documentID.isEmpty {
            var dataArray: Array<String> = []
            let group = DispatchGroup()
            group.enter() // initial enter
            
            let docRef = Firestore.firestore().collection(collectionName).document(documentID)
            docRef.getDocument() { (document, error) in
                group.enter()
                if error != nil {
                    print("Error getting amount of recipes in last seen")
                } else {
                    dataArray.append(document!.documentID) // Just appending ID as it is a String
                    group.leave()
                }
                group.leave() // Initial leave
            }
            
            group.notify(queue: DispatchQueue.global(qos: .background)) {
                completing(dataArray)
            }
        }
        
    }
    
}
于 2020-08-20T12:27:46.157 回答