使用异步 Firebase 调用 SwiftUI

Working With Async Firebase Calls SwiftUI

我知道 Firebase getDocument 调用是异步的,所以我想弄清楚如何基本上等到调用完成执行,然后继续做其他事情。

我已经尝试使用 DispatchGroup() 和 entering/leaving 组,但我似乎无法使其正常工作。我有类似以下内容:

let myGroup = DispatchGroup()
let usersRef = self.db.collection("Users").document("Users").collection("Users")
if self.testCondition == false {
    self.errorMessage = "error"
} else{
    usersRef.getDocuments {(snap, err) in
        myGroup.enter()
        //basically getting every username
        for document in snap!.documents{
            let user = document["username"] as! String
            let userRef = usersRef.document(user)
            userRef.getDocument { (snapshot, err) in
                if err != nil {
                    print(err)
                } else {
                    let sample = snapshot!["sample"] as! String
                    if sample == 'bad' {
                        self.errorMessage = "error"
                    }
                }
            }
        }
        myGroup.leave()
    }
    print("what4")
    //I would like it so that I can execute everything in a code block like this
    //after the async call finishes
    myGroup.notify(queue: .main) {
        print("Finished all requests.")
        //THEN DO MORE STUFF
    }
}

如何修改此处的 myGroup.enter() 和 myGroup.leave() 位置,以便在 Firebase 调用完成后,我可以继续执行代码?

谢谢!

这稍微解释了 DispatchGroup()

您的代码中只有一个小错误,那么它应该可以正常工作。 确保 enter() Firebase getDocuments() 调用之外的组。由于这已经提出请求并需要时间,因此该过程将继续。

这个简单的小例子应该可以帮助您理解它:

func dispatchGroupExample() {
        
        // Initialize the DispatchGroup
        let group = DispatchGroup()
        
        print("starting")
        
        // Enter the group outside of the getDocuments call
        group.enter()
        
        let db = Firestore.firestore()
        let docRef = db.collection("test")
        docRef.getDocuments { (snapshots, error) in
            
            if let documents = snapshots?.documents {
                for doc in documents {
                    print(doc["name"])
                }
            }
            
            // leave the group when done
            group.leave()
        }
        
        // Continue in here when done above
        group.notify(queue: DispatchQueue.global(qos: .background)) {
            print("all names returned, we can continue")
        }
    }

等待多个异步调用时,在您离开组后立即让return的异步函数中使用completing。完整例如。下面:

class Test {
    
    init() {
        self.twoNestedAsync()
    }
    
    func twoNestedAsync() {
        let group = DispatchGroup() // Init DispatchGroup
        
        // First Enter
        group.enter()
        print("calling first asynch")
        
        self.dispatchGroupExample() { isSucceeded in
            
            // Only leave when dispatchGroup returns the escaping bool
            
            if isSucceeded {
                group.leave()
            } else {
                // returned false
                group.leave()
            }
        }
        
        // Enter second
        group.enter()
        print("calling second asynch")
        
        self.waitAndReturn(){ isSucceeded in
            
            // Only return once the escaping bool comes back
            if isSucceeded {
                group.leave()
            } else {
                //returned false
                group.leave()
            }
            
        }
        
        group.notify(queue: .main) {
            print("all asynch done")
        }
    }
    
    // Now added escaping bool which gets returned when done
    func dispatchGroupExample(completing: @escaping (Bool) -> Void) {
        
        // Initialize the DispatchGroup
        let group = DispatchGroup()
        
        print("starting")
        
        // Enter the group outside of the getDocuments call
        group.enter()
        
        let db = Firestore.firestore()
        let docRef = db.collection("test")
        docRef.getDocuments { (snapshots, error) in
            
            if let documents = snapshots?.documents {
                for doc in documents {
                    print(doc["name"])
                }

                // leave the group when succesful and done
                group.leave()
            }
            
            if let error = error {
                // make sure to handle this
                completing(false)
                group.leave()
            }
        }
        
        // Continue in here when done above
        group.notify(queue: DispatchQueue.global(qos: .background)) {
            print("all names returned, we can continue")
            
            //send escaping bool.
            completing(true)
        }
    }
    
    func waitAndReturn(completing: @escaping (Bool) -> Void) {
        DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(2), execute: {
            print("Done waiting for 2 seconds")
            completing(true)
        })
    }
}

这为我们提供了以下输出: