如何使用DispatchGroup/GCD快速执行函数? [英] How do I use DispatchGroup / GCD to execute functions sequentially in swift?

查看:70
本文介绍了如何使用DispatchGroup/GCD快速执行函数?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在刷新集合视图之前,我需要依次运行两个函数.第一个函数从firebase中提取autoid,并将其写入数组.然后,第二个函数(getLocation)使用该数组对Firebase进行另一个调用,以检索每个autoid下的值(位置).

I need to run two functions sequentially before I refresh my collection view. The first function pulls autoids from firebase and writes them into an array. The second function (getLocation) then uses that array to make another call to firebase to retrieve a value (location) beneath each autoid.

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

I'm using DispatchGroup() to ensure the first function finishes before the second one begins. But I also need the second function to complete before the notify refreshes the collection view.

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

I've written a basic for loop to test the DispatchGroup() in the second function and was able to get it to execute but I can't get it to work properly when I use it to actually fetch data from firebase.

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

Wondering if I may be entering and leaving in the wrong place? Here are my functions.

DispatchGroup

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.

So I call each function then use dispatchGroup.notify.

  getEvents()
  getLocation()


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

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

This is the first time I've used DispatchGroups, so any tips or recommendations are welcomed.

推荐答案

当我正确理解您的意图后,您希望:

When I understand your intent correctly, you want to:

  • 获取事件ID
  • 对于每个事件ID,您要获取位置

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

I would suggest to use two different dispatch groups:

  • 第一个,eventDispatchGroup,将在我们获得新事件之前进入,并在所有事件都添加到数组之后离开.当通知该组时,所有事件都在数组中,因此我们调用getLocation(注意:该数组是否将被清除/重置,或者在后续调用中无限增长,可能是因为重复吗?)
  • getLocation中,我们使用第二个locationDispatchGroup在获取位置之前输入,并在获取所有位置之后离开.收到通知后,该组将更新视图等.(注意:是否还会在某个时间点清除位置数组?)
  • 呼叫者仅需呼叫getEvents,然后(在通知块中)呼叫getLocation.
  • the first, eventDispatchGroup, will enter before we get new events, and will leave after all the events have been added to the array. When this group gets notified, all the events are in the array, so we call getLocation (NOTE: Will this array ever be cleared / resetted, or will it grow unlimitedly upon subsequent calls, likely with duplicates in it?)
  • In getLocation, we use a second locationDispatchGroup that we enter before we get the locations, and leave after all the locations have been fetched. Upon notification, this group will update the view etc. (NOTE: Will the location array also be cleared at some point in time?)
  • The caller will only have to call getEvents, which then (in the notification block) calls getLocation.

您要记住的是:

  • DispatchGroup.enter()leave()调用必须保持平衡.因此,如果您无法确定某个事件的位置,则仍然必须调用leave(),否则将不会调用notify()
  • 在处理完所有数据之后,
  • 始终在观察者代码外部调用enter(),并在其内部调用leave().
  • DispatchGroup.enter() and leave() calls have to be balanced. So if you somehow cannot determine the location to some event, you still have to call leave(), otherwise notify() won't be called
  • Always call enter() outside the observer code, and leave() inside of it, after all data has been processed.

这是一个可能的解决方案:

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

}

这篇关于如何使用DispatchGroup/GCD快速执行函数?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆