简体   繁体   中英

How to wait for multiple firebase queries to finish before executing a task?

I'm trying to figure out how to delete all saved User's data, and once that data is deleted, Signout the user and delete their account when deleteUserAccount() is called.

Right now, when the User presses the "Delete Account" button, their account gets deleted, but the data still remains on firebase because the completion handler gets called before the deleteAllUserTicketData() function has enough time to execute the query and delete the appropriate documents.

My question is, how can I wait for the queries to execute and all the documents to get deleted before executing the completion handler in order to sign the user out and delete their account?

Much appreciated! Thanks in advanced!

        func deleteAllUserTicketData(completion: @escaping () -> Void) {
            self.rootWsrCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for wsr in snapshot.documents{
                    print("Deleting WSR's")
                    self.rootWsrCollection!.document(wsr.documentID).delete()
                }
            }
    
            self.rootExerciseCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for exercise in snapshot.documents {
                    print("Deleting Exercises")
                    self.rootExerciseCollection!.document(exercise.documentID).delete()
                }
            }
    
            self.rootWorkoutsCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for workout in snapshot.documents {
                    print("Deleting Workouts")
                    self.rootWorkoutsCollection!.document(workout.documentID).delete()
                }
            }
    
            self.workoutsCollection.daysCollection.removeAll()
            completion()
        }
    


        func deleteUserFromFirestore(completion: @escaping () -> Void) {
            self.rootUserCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for user in snapshot.documents {
                    self.rootUserCollection!.document(user.documentID).delete()
                }
                completion()
            }
        }


    
        func deleteUserAccount() {
            deleteAllUserTicketData {
                self.deleteUserFromFirestore {
                    Auth.auth().currentUser?.delete()
                }
            }
        }

You can try DispatchGroup to wait for all async then trigger when they all finish. If you enter() 5 times, you also need to leave() 5 times. You need to balance the leave() with enter() . If you call leave() more than enter() , it will crash because unbalanced call.

And, please do not use addSnapShotListener if you don't need to make a realtime observer. Use this instead https://firebase.google.com/docs/firestore/query-data/get-data#get_a_document

Here is you updated logic:

        func deleteAllUserTicketData(completion: @escaping () -> Void) {
            let dispatchGroup = DispatchGroup()

            dispatchGroup.enter()
            self.rootWsrCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener {[weak self] (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for wsr in snapshot.documents{
                    print("Deleting WSR's")
                    self?.rootWsrCollection!.document(wsr.documentID).delete()
                    // use can try this for shortened call
                    wsr.delete()
                }
                // Suppose that delete() is success
                dispatchGroup.leave()
            }

            dispatchGroup.enter()
            self.rootExerciseCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener {(querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for exercise in snapshot.documents {
                    print("Deleting Exercises")
                    exercise.delete()
                }
                dispatchGroup.leave()
            }

            dispatchGroup.enter()
            self.rootWorkoutsCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for workout in snapshot.documents {
                    print("Deleting Workouts")
                    workout.delete()
                }
                dispatchGroup.leave()
            }
            
            // When no waiting item remains (all entered and left), this block will be triggered on queue, in this case, is it Global queue (like background thread
            // So if you need to update UI from this, you need to switch to Main Queue or DispatchQueue.main.async { }
            dispatchGroup.notify(queue: DispatchQueue.global()) { [weak self] in
                // refer to self with a weak reference to avoid retain cycle, prevent memory leak
                self?.workoutsCollection.daysCollection.removeAll()
                completion()
            }
        }

        func deleteUserFromFirestore(completion: @escaping () -> Void) {
            self.rootUserCollection?.whereField("uid", isEqualTo: userIdRef).addSnapshotListener { (querySnapshot, err) in
                guard let snapshot = querySnapshot else { return }
                for user in snapshot.documents {
                    user.delete()
                }
                completion()
            }
        }
    
        func deleteUserAccount() {
            self.deleteAllUserTicketData { [weak self] in
                self?.deleteUserFromFirestore {
                    Auth.auth().currentUser?.delete()
                }
            }
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM