Bo Jackson
Bo Jackson

Reputation: 357

Dispatch Group Errors

So I am trying to restructure my API calls to make use of dispatchGroups so I don't have to make collectionViews and other elements reload so quick. I know that with dispatch groups you typically have to create one, enter, and then leave a certain number of times. Upon completion of this, you typically notify the main queue to do some operation. However, in the code snippet below it notifies the main queue before I even enter the dispatch group once. Which is throwing things way off. If anyone could look at my code and tell me what's going wrong I would really appreciate that.

 static func showFeaturedEvent(for currentLocation: CLLocation,completion: @escaping ([Event]) -> Void) {
        //getting firebase root directory
        let dispatchGroup1 = DispatchGroup()
        var currentEvents:[Event]?
        var geoFireRef: DatabaseReference?
        var geoFire:GeoFire?
        geoFireRef = Database.database().reference().child("featuredeventsbylocation")
        geoFire = GeoFire(firebaseRef: geoFireRef!)
        let circleQuery = geoFire?.query(at: currentLocation, withRadius: 17.0)
        circleQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
            print("Key '\(key)' entered the search area and is at location '\(location)'")
            dispatchGroup1.enter()
            print("entered dispatch group")
            EventService.show(forEventKey: key, completion: { (event) in
                if let newEvent = event {
                    currentEvents?.append(newEvent)
                    dispatchGroup1.leave()
                    print("left dispatch group")
                }
            })

        })
        dispatchGroup1.notify(queue: .main, execute: {
            if let currentEventsFinal = currentEvents{
                completion(currentEventsFinal)
            }
        })
    }

I am running dispatch groups in other places. Im not sure if that would affect anything but I just felt like it was important to note in this question.

Upvotes: 1

Views: 1204

Answers (1)

Paulw11
Paulw11

Reputation: 114836

You need to enter the group before you start the asynchronous task and leave in the completion of the asynchronous task. You aren't executing the first enter until the first asynchronous task completes, so when execution hits your notify the dispatch group is empty and it fires straight away.

It is also important that you call leave the same number of times that you call enter or the group will never empty, so be wary of calling leave inside conditional statements.

static func showFeaturedEvent(for currentLocation: CLLocation,completion: @escaping ([Event]) -> Void) {
    //getting firebase root directory
    let dispatchGroup1 = DispatchGroup()
    var currentEvents:[Event]?
    var geoFireRef: DatabaseReference?
    var geoFire:GeoFire?
    geoFireRef = Database.database().reference().child("featuredeventsbylocation")
    geoFire = GeoFire(firebaseRef: geoFireRef!)
    let circleQuery = geoFire?.query(at: currentLocation, withRadius: 17.0)

    disatchGroup1.enter()

    circleQuery?.observe(.keyEntered, with: { (key: String!, location: CLLocation!) in
        print("Key '\(key)' entered the search area and is at location '\(location)'")

        dispatchGroup1.enter()

        EventService.show(forEventKey: key, completion: { (event) in
            if let newEvent = event {
                currentEvents?.append(newEvent)
                print("left dispatch group")
            }

            dispatchGroup1.leave()

        })

        dispatchGroup1.leave()

    })

    dispatchGroup1.notify(queue: .main, execute: {
        if let currentEventsFinal = currentEvents{
            completion(currentEventsFinal)
        }
    })
}

Upvotes: 1

Related Questions