GCD未按阻止顺序执行

时间:2016-08-09 21:43:50

标签: swift firebase grand-central-dispatch firebase-realtime-database

我正在尝试从我的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
}

1 个答案:

答案 0 :(得分:3)

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

坦率地说,在这里使用调度组可能不合适。调度组的概念是每个"进入"匹配相应的"离开"。你正在打电话"输入"曾经,但不清楚你有什么保证观察者最终会被召唤多少次。

但是在这种情况下,你正在处理一个"观察者",一些将被调用的代码块,但事件发生的次数很多。它可能根本不会发生。它可能会发生很多次。这只是观察事件发生次数的问题。

现在,如果你肯定知道这只会被调用一次,那么从技术上讲这种模式就可以了。但是,如果它只被召唤一次,那么你根本不需要一个派遣小组。