GCD 未按块顺序执行

GCD Not Executing In Block Order

我正在尝试从我的 Firebase 数据库中检查某些节点是否存在,如果不存在,则在数据库中创建新节点。我需要我的方法 loadAll() 在它调用创建任何缺失节点的第二个方法 autoCheck 之前完全执行。我尝试了一个调度组来执行此操作,但它不起作用,print("Done downloading!") 在完成检查数据库之前被调用。谢谢!!

代码:

func loadAll(){
    var deleted_load = false
    var poor_load = false
    var allLoadDone = false

    if let user = FIRAuth.auth()?.currentUser {
        let uid = user.uid

        let refff = FIRDatabase.database().reference()
        let userRef = refff.childByAppendingPath("users/\(uid)")


        //When making new fields increase this var
        var howmany = 2
        var done = 0

        var downloadGroup = dispatch_group_create()
        dispatch_group_enter(downloadGroup)
        userRef.queryOrderedByValue().observeEventType(.ChildAdded, withBlock: { snapshot in
            allLoadDone = true
            if(!snapshot.exists()){
                print("ERR DOES NOT EXCIST")
                self.autoCheck(deleted_load, poor_load: poor_load, userRef: userRef, ig: 1)
                return
            }
            if let score = snapshot.value as? Int {
                if(snapshot.key=="deleted"){
                    deleted_load = true
                }
                if(snapshot.key=="Staff_Poor"){
                    poor_load = true
                }
                print("\(snapshot.key) is \(score)")
                self.counter.text = String(score)
            }
            done = done + 1
            if(done>=(howmany)){
                self.autoCheck(deleted_load, poor_load: poor_load, userRef: userRef, ig: 2)
            }
        })
            dispatch_group_leave(downloadGroup)

        dispatch_group_notify(downloadGroup, dispatch_get_main_queue()) { // 2
            print("Done downloading!")
        }
    } else {
        print("No user!")
        gotoLogin()
    }
}

func autoCheck(deleted_load: Bool, poor_load: Bool, userRef: FIRDatabaseReference, ig: Int) -> Bool{
    print("ID IS: \(ig)")
    var newUserData = ["deleted": 0, "Staff_Poor": 0]
    print("deleted_load: \(deleted_load)")
    if deleted_load==true{
        newUserData.removeValueForKey("deleted")
    }
    print("poor_load: \(poor_load)")
    if poor_load==true{
        newUserData.removeValueForKey("Staff_Poor")
    }
    if(!newUserData.isEmpty){
        userRef.updateChildValues(newUserData)
    }

    return true
}

您对 dispatch_group_leave(downloadGroup) 的调用必须放在完成处理程序闭包中。现在,你把它放在外面,这意味着该组将在异步调用完成之前完成。

但让我们退后一步,了解调度组的用途。典型的模式是在执行一系列异步任务时使用调度组,并且您想知道它们何时完成。因此,对于每个任务,您在调用某个异步过程之前进入该组,然后将该组留在该异步过程的完成处理程序中,例如:

let group = dispatch_group_create()

for object in arrayOfObjects {
    dispatch_group_enter(group)
    performSomeAsynchronousActionWithObject(object) { result in 
        // do something with `result`
        ...
        dispatch_group_leave(group)
    }
}

dispatch_group_notify(group, dispatch_get_main_queue()) {
    print("done performing asynchronous task with all of those objects")
}

坦率地说,在这里使用调度组可能不合适。调度组的概念是每个 "enter" 都与相应的 "leave" 相匹配。您正在调用 "enter" 一次,但不清楚您能否保证观察者最终会被调用多少次。

但在这种情况下,您处理的是 "observer" 一些将被调用的代码块,无论事件发生了多少次。它可能根本不会发生。它可能会发生很多次。这只是观察到的事件发生了多少次的问题。

现在,如果您确定这将被调用一次且仅调用一次,那么从技术上讲,这种模式是可行的。但是如果它只被调用一次,那么你根本不需要调度组。