1

我在单个用户 tapGesture 中运行多个 Firestore 查询,这要求我确保应用程序中运行的同时 Firestore 查询最少或没有。我已经阅读了关于这个问题的多个答案(等待任务完成),但我的查询没有按照我想要的顺序运行。

感谢您帮助指导我使用 DispatchGroup 以确保代码和查询的逻辑顺序。

我想确保函数checkAndCreateUserWorkoutProfile中的 Firestore 查询在DispatchGroup.notify(...)中的 2 个打印语句之前完成,从“Firestore Sequence”方法开始。相反,查询在两个打印语句启动后完成。

下面是我的 Xcode 调试器的代码和屏幕截图。如屏幕截图所示,问题在于使用“ DispatchGroup.notify(...) ”并没有等到函数 checkAndCreateUserWorkoutProfile中的 Firestore 查询完成。

alert.addAction(UIAlertAction(title: "Select", style: .default, handler: { [self]_ in
            
            let dispatchGroup = DispatchGroup()
            
            dispatchGroup.enter()
            
            DispatchQueue.main.async {
                print("Firestore Sequence 2 Initiated")
                startActivityIndicator()
                
                if let user = Auth.auth().currentUser {
                    let userID = user.uid
                    
                    db.collection("user").whereField("author_uid", isEqualTo: userID).getDocuments { snapshot, error in
                        
                        if error == nil && snapshot != nil {
                            
                            for document in snapshot!.documents {
                            
                            let docID = document.documentID
                            
                            db.collection("user")
                                .document(docID)
                                .setData(["selectedWorkoutID" : workoutRow.workoutId], merge: true)
                                    
                            print("Firestore Sequence 2 Success - user selectedWorkoutID updated")
                                
                            }
                        }
                        dispatchGroup.leave()
                        
                        if let user = Auth.auth().currentUser {
                            let userID = user.uid
                            checkAndCreateUserWorkoutProfile(selectedWorkout: workoutRow, userID: userID)
                        }
                    }
                }
            }

            dispatchGroup.notify(queue: .main) {
                print("Firestore Sequence 4 Initiated")
                print("Firestore Sequence 5 Initiated - Create/Read User Specific Dayprogram data")
                }

        }))

func checkAndCreateUserWorkoutProfile(selectedWorkout: Workout, userID: String) {

        print("Firestore Sequence 3 Initiated - createORread user specific workout profile")
        
        let dispatchGroup = DispatchGroup()
        
        dispatchGroup.enter()
        
        db.collection("Workout")
            .whereField("workoutId", isEqualTo: selectedWorkout.workoutId)
            .whereField("userID", isEqualTo: userID)
            .getDocuments() { (querySnapshot, err) in
                
                if querySnapshot?.count == 0 {

                    var ref: DocumentReference? = nil
                  
                    ref = self.db.collection("Workout").addDocument(data:
                        [
                        "author_uid": selectedWorkout.author_uid!,
                        "workoutId": selectedWorkout.workoutId,
                        "userID": userID
                        ])

                     { err in
                        if let err = err {
                            print("Error adding user specific workout profile: \(err)")
                            dispatchGroup.leave()
                        } else {
                            print("Firestore Sequence 3 Success - User specific workout profile added/created with ID: \(ref!.documentID)")
                            dispatchGroup.leave()
                        }
                    }
                    
                    
                } 
                
            }

        }

在此处输入图像描述

使用@Kiril S. 的回答,代码已得到更正,如下所示。

class WorkoutViewController: UIViewController {

let dispatchGroup = DispatchGroup()


alert.addAction(UIAlertAction(title: "Select", style: .default, handler: { [self]_ in
            
            dispatchGroup.enter()
            
            DispatchQueue.main.async {
                print("Firestore Sequence 2 Initiated")
                startActivityIndicator()
                
                if let user = Auth.auth().currentUser {
                    let userID = user.uid
                    
                    db.collection("user").whereField("author_uid", isEqualTo: userID).getDocuments { snapshot, error in
                        
                        if error == nil && snapshot != nil {
                            
                            for document in snapshot!.documents {
                            
                            let docID = document.documentID
                            
                            db.collection("user")
                                .document(docID)
                                .setData(["selectedWorkoutID" : workoutRow.workoutId], merge: true)
                                    
                            print("Firestore Sequence 2 Success - user selectedWorkoutID updated")
                                
                            }
                        }
                        
                        
                        if let user = Auth.auth().currentUser {
                            let userID = user.uid
                            checkAndCreateUserWorkoutProfile(selectedWorkout: workoutRow, userID: userID)
                         dispatchGroup.leave()
                        }
                    }
                }
            }

            dispatchGroup.notify(queue: .main) {
                print("Firestore Sequence 4 Initiated")
                print("Firestore Sequence 5 Initiated - Create/Read User Specific Dayprogram data")
                }

        }))

func checkAndCreateUserWorkoutProfile(selectedWorkout: Workout, userID: String) {

        print("Firestore Sequence 3 Initiated - createORread user specific workout profile")
        
        dispatchGroup.enter()
        
        db.collection("Workout")
            .whereField("workoutId", isEqualTo: selectedWorkout.workoutId)
            .whereField("userID", isEqualTo: userID)
            .getDocuments() { (querySnapshot, err) in
                
                if querySnapshot?.count == 0 {

                    var ref: DocumentReference? = nil
                  
                    ref = self.db.collection("Workout").addDocument(data:
                        [
                        "author_uid": selectedWorkout.author_uid!,
                        "workoutId": selectedWorkout.workoutId,
                        "userID": userID
                        ])

                     { err in
                        if let err = err {
                            print("Error adding user specific workout profile: \(err)")
                            self.dispatchGroup.leave()
                        } else {
                            print("Firestore Sequence 3 Success - User specific workout profile added/created with ID: \(ref!.documentID)")
                            self.dispatchGroup.leave()
                        }
                    }     
                }      
            }
        }

Xcode 控制台显示更正的代码/查询序列。 在此处输入图像描述

4

1 回答 1

2

所以基本上现在发生了什么:

  • 警报行动开始
  • 创建let dispatchGroup = DispatchGroup()
  • 进入那个组
  • 离开组 ==>dispatchGroup.notify火灾
  • checkAndCreateUserWorkoutProfile开始,创建自己的调度组等等(已经错了,没关系)

所以你有两个问题:

  1. 您必须有 1 个调度组,而不是每个功能的单独组。所以转到let dispatchGroup = DispatchGroup()类成员级别,这样两个函数都在同一个调度组中。

  2. 并且您checkAndCreateUserWorkoutProfile需要 在之前的呼叫离开之前进入调度组。所以顺序应该改为

    if let user = Auth.auth().currentUser {
        let userID = user.uid
        checkAndCreateUserWorkoutProfile(selectedWorkout: workoutRow, userID: userID)
    }
    dispatchGroup.leave()
    

那样:

  • 警报行动开始
  • 进入定义为类成员的组
  • Calls checkAndCreateUserWorkoutProfile,它进入同一个调度组并开始它的异步调用
  • 警报操作离开组(但通知不会触发,因为checkAndCreateUserWorkoutProfile尚未离开组)
  • checkAndCreateUserWorkoutProfile最终离开小组 ==>dispatchGroup.notify火灾
于 2021-12-18T20:41:09.427 回答