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.
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.
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
let dispatchGroup = DispatchGroup()
Functions:
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()
} })
}
So I call each function then use dispatchGroup.notify.
getEvents()
getLocation()
dispatchGroup.notify(queue: .main) {
print(self.locationsArray)
self.eventsCollectionView.reloadData()
}
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:
- Get event IDs
- For each event ID, you want to get the Location
I would suggest to use two different dispatch groups:
- 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 callgetLocation
(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 secondlocationDispatchGroup
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) callsgetLocation
.
What you'll have to keep in mind is:
DispatchGroup.enter()
andleave()
calls have to be balanced. So if you somehow cannot determine the location to some event, you still have to callleave()
, otherwisenotify()
won't be called- Always call
enter()
outside the observer code, andleave()
inside of it, after all data has been processed.
Here is one possible solution:
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()
}
}
}
来源:https://stackoverflow.com/questions/48740148/how-do-i-use-dispatchgroup-gcd-to-execute-functions-sequentially-in-swift