如何使用DispatchGroup / GCD在swift中按顺序执行函数?

时间:2018-02-12 05:40:52

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

在刷新集合视图之前,我需要按顺序运行两个函数。第一个函数从firebase中提取autoid并将它们写入数组。然后,第二个函数(getLocation)使用该数组再次调用firebase来检索每个autoid下面的值(位置)。

我正在使用DispatchGroup()来确保第一个函数在第二个函数开始之前完成。但是我还需要在通知刷新集合视图之前完成第二个函数。

我已经编写了一个基本的for循环来测试第二个函数中的DispatchGroup()并且能够让它执行但是当我用它来实际从firebase获取数据时我无法正常工作。

想知道我是否可能在错误的地方进出?这是我的功能。

DispatchGroup

let dispatchGroup = DispatchGroup()

功能:

 func getLocation() {
        self.dispatchGroup.enter()
        for i in 0..<self.eventsArray.count {
                let eventid = self.eventsArray[i]
                self.ref.child("Events").child(eventid).observe(.value, with: { (snapshot) in
                    if let dictionary = snapshot.value as? [String: AnyObject] {

                        let location = dictionary["location"] as! String
                        self.locationsArray.append(location)
                    } })
            }
        self.dispatchGroup.leave()
    }


 func getEvents() {

            self.dispatchGroup.enter()
            Database.database().reference().child("Events").observe(DataEventType.value, with: { (snapshot) in
                if let dictionary = snapshot.children.allObjects as? [DataSnapshot] {
                    for child in dictionary {
                        let eventid = child.key
                        self.eventsArray.append(eventid)

                    }
                     self.dispatchGroup.leave()
                } })  
        }

所以我调用每个函数然后使用dispatchGroup.notify。

  getEvents()
  getLocation()


  dispatchGroup.notify(queue: .main) {
       print(self.locationsArray)
       self.eventsCollectionView.reloadData()
  }

这是我第一次使用DispatchGroups,因此欢迎任何提示或建议。

1 个答案:

答案 0 :(得分:0)

当我理解你的意图时,你想要:

  • 获取活动ID
  • 对于每个事件ID,您希望获取位置

我建议使用两个不同的调度组:

  • 第一个eventDispatchGroup将在我们获取新事件之前进入,并且在所有事件都添加到数组后将离开。当该组收到通知时,所有事件都在数组中,因此我们调用getLocation注意:此数组是否会被清除/重置,或者在后续调用时无限增长,可能有重复吗?)
  • getLocation中,我们使用在获取位置之前输入的第二个locationDispatchGroup,并在获取所有位置后离开。收到通知后,该组将更新视图等。(注意:位置数组是否也会在某个时间点被清除?)
  • 来电者只需拨打getEvents,然后(在通知栏中)拨打getLocation

您必须记住的是:

  • DispatchGroup.enter()leave()来电必须保持平衡。因此,如果您以某种方式无法确定某个活动的位置,您仍然需要致电leave(),否则notify()将被称为
  • 在处理完所有数据后,始终在观察员代码之外调用enter(),并在其内部调用leave()

以下是一个可能的解决方案:

class A {
    var eventDispatchGroup = DispatchGroup()
    var locationDispatchGroup = DispatchGroup()
    var eventsArray = [String]()
    var locationsArray = [String]()

    func getEvents() {
        // clean self.eventsArray here??
        eventDispatchGroup.enter()
        Database.database().reference().child("Events").observe(DataEventType.value, with: { (snapshot) in
            if let dictionary = snapshot.children.allObjects as? [DataSnapshot] {
                for child in dictionary {
                    let eventid = child.key
                    self.eventsArray.append(eventid)
                }
            }
            eventDispatchGroup.leave();
        })
        eventDispatchGroup.notify(queue: .main) {
            getLocation()
        }
    }

    func getLocation() {
        // clean self.locationsArray here?
        for i in 0..<self.eventsArray.count {
            locationDispatchGroup.enter()
            let eventid = self.eventsArray[i]
            self.ref.child("Events").child(eventid).observe(.value, with: { (snapshot) in
                if let dictionary = snapshot.value as? [String: AnyObject] {

                    let location = dictionary["location"] as! String
                    self.locationsArray.append(location)
                }
                locationDispatchGroup.leave()
            })
        }

        locationDispatchGroup.notify(queue: .main) {
            print(self.locationsArray)
            self.eventsCollectionView.reloadData()
        }
    }

}