【问题标题】:Working With Async Firebase Calls SwiftUI使用异步 Firebase 调用 SwiftUI
【发布时间】:2020-10-23 16:23:30
【问题描述】:

我知道 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的一个很好的例子。 不是此 API 的目的是强制单个异步任务变为同步。而等待异步任务的完成通常是错误的方法。推荐的方法是将 //THEN DO MORE STUFF 移动到 getDocuments 闭包内的循环末尾或添加完成处理程序。

标签: swift firebase google-cloud-firestore swiftui dispatch


【解决方案1】:

这稍微解释了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")
        }
    }

等待多个异步调用时,在异步函数中使用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)
        })
    }
}

这给了我们以下输出:

【讨论】:

  • 这是一个很好的例子。当我们有嵌套的异步调用时,你能给出一个类似的吗?说两个嵌套的异步调用。
  • 我添加了一个例子。不确定我是否理解正确。让我知道这是否满足您的需求
  • 永远祝福兄弟!这对我有帮助!
  • 嘿@Simon 非常感谢这个,非常有帮助,让我做一些我想做的事情。我意识到我认为我也在使用嵌套的异步函数,请参见此处:stackoverflow.com/questions/62723265/… 那么我是否应该尝试像您的第二个示例一样进行镜像?
  • 是的,我会向您推荐我在这里添加的多异步调用。尽管如此,我也回答了你的其他问题
猜你喜欢
  • 1970-01-01
  • 2021-11-05
  • 2022-06-27
  • 1970-01-01
  • 2019-11-15
  • 2022-11-14
  • 2018-07-07
  • 2020-06-10
  • 2022-12-03
相关资源
最近更新 更多