swift - 使用异步 Firebase 调用 SwiftUI

标签 swift firebase google-cloud-firestore swiftui dispatch

我知道 Firebase getDocument 调用是异步的,因此我试图找出如何本质上等待调用完成执行,然后继续执行其他操作。

我尝试过使用 DispatchGroup() 并进入/离开组,但我似乎无法让它正常工作。我有类似以下内容:

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()

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

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

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")
        }
    }

等待多个异步调用时,请在异步函数中使用完成,让您在离开组后立即返回。完整例如。如下:

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)
        })
    }
}

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

DispatchGroup with completing and escaping output

关于swift - 使用异步 Firebase 调用 SwiftUI,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62707020/

相关文章:

swift - 如何使用 Perform(withKeyModifier :block:) function in XCUITest

ios - 制作模式以使用 NSRegularExpression

firebase - Flutter 从 Firebase Cloud Firestore 返回完整数组

ios - ResearchKit 步行任务不返回心率数据

javascript - 如何根据数据库用户 ID(不是 uid)设置 firebase 规则

android - 如何使 Firebase 邀请在模拟器上工作?

ios - 当项目从运行单个目标的多环境配置时,收到[上传处理所需的缺少的 dSYM]

ios - 在 Firestore 中获取数据

javascript - 为什么我的 JavaScript 日期/时间对象在 Cloud Firestore 中存储为 map 而不是时间戳?

swift - 如何倒带SKEmitterNode的时间?