Search code examples
iosswiftasynchronousdeferredclgeocoder

Why is defer block executed before a closure finishes in the same function


I wrote the following function to add a map annotation that uses CLGeocoder() to resolve the location name given a coordinate. I use a defer block to get the resolved location name. However, the defer block seems to finish before the closure finishes. Why?

Below is my code:

func addAnnotation(gestureRecognizer: UIGestureRecognizer) {
    var locationNameStr = ""
    defer {
        let newPin = Pin(dictionary: locationDictionary, context: sharedContext)
        newPin.name = locationNameStr

        do {
            //persist the new pin to core data
            try sharedContext.save()
            showPinOnMap(newPin)
        } catch let error as NSError {
            print("error saving the new pin in context")
        }
    }

    // use CLGeocoder to resolve the location name as title of the annotation
    CLGeocoder().reverseGeocodeLocation(CLLocation(latitude: newCoordinate.latitude, longitude: newCoordinate.longitude), completionHandler: {(placemarks, error) -> Void in

        if error != nil {
            print("reverse geocoding failed with error: \(error)")
            //return
        } else if placemarks!.count > 0 {
            let firstPlace = placemarks![0] as CLPlacemark

            if firstPlace.country != nil {
                locationNameStr = "a place in \(firstPlace.country!)"
            }
            else if firstPlace.locality != nil {
                locationNameStr = "a place in \(firstPlace.locality!)"
            }
            print("location name: \(locationNameStr)")
        }
    })
}

Solution

  • reverseGeocodeLocation(_:completionHandler:) executes asynchronously, it makes sense that the code in your defer block is executing before the closure passed as the completionHandler argument is invoked

    is there a reason that the code in your defer block can't be moved in to your completion handler?