Using a value after it has been set by asynchronous code

By now you may have read this post explaining what “asynchronous” means. If you haven’t, please read it first!

So, if you understand what “asynchronous” means, then you won’t make the biggest mistake that people tend to make with asynchronous code, namely: outside asynchronous code, trying to use a value that depends on asynchronous code.

Here’s an actual example someone posted on Stack Overflow. First, the programmer has some instance properties in his class:

var placemarkLongitude = CLLocationDegrees()
var placemarkLatitude = CLLocationDegrees()

Then, in a method, he does some geocoding, like this:

self.geocoder.geocodeAddressString(combinedAddress, completionHandler: {(placemarks, error) -> Void in
    if let placemark = placemarks?[0] {
        let placemark = placemarks![0]
        self.placemarkLatitude = (placemark.location?.coordinate.latitude)!
        self.placemarkLongitude = (placemark.location?.coordinate.longitude)!
    }
}))
let eventLatitude = self.placemarkLatitude // 0.0!
let eventLongitude = self.placemarkLongitude // 0.0!

The programmer here is surprised because he can see perfectly well that he sets self.placemarkLatitude and self.placemarkLongitude — but when he tries to use those values in the last two lines, they are zero. It’s as if they never got set in the first place. What happened?

If you understand what “asynchronous” means, you understand what’s gone wrong here. The programmer has not grasped that the code runs in a different order from the way it is written. The completionHandler code in geocoding is asynchronous. Therefore, the last two lines run before the asynchronous code! Like this:

// 1
self.geocoder.geocodeAddressString(combinedAddress, completionHandler: {(placemarks, error) -> Void in
    // 4! much later than 3
    if let placemark = placemarks?[0] {
        // 5
        let placemark = placemarks![0]
        // 6
        self.placemarkLatitude = (placemark.location?.coordinate.latitude)!
        // 7
        self.placemarkLongitude = (placemark.location?.coordinate.longitude)!
    }
}))
// 2
let eventLatitude = self.placemarkLatitude // 0.0!
// 3
let eventLongitude = self.placemarkLongitude // 0.0!

First (2) he fetches self.placemarkLatitude and (3) self.placemarkLongitude and sets his local variables eventLatitude and eventLongitude. Then, some time later — possibly quite a long time later — (4) the geocoding completes, the completion handler is called, and (6) he sets self.placemarkLatitude and (7) self.placemarkLongitude — too late to use them!

This programmer is trying to use a value before it has been set! That is impossible, unless you happen to have a time machine in your pocket. That’s a typical trap you can fall into, if you don’t understand what “asynchronous” means.

Do you see how to solve the problem? The code that is meant to run after the geocoding finishes — and after self.placemarkLatitude and self.placemarkLongitude has been set by the asynchronous code — needs to be moved into the asynchronous code, like this:

// 1
self.geocoder.geocodeAddressString(combinedAddress, completionHandler: {(placemarks, error) -> Void in
    // 2, some time later
    if let placemark = placemarks?[0] {
        // 3
        let placemark = placemarks![0]
        // 4
        self.placemarkLatitude = (placemark.location?.coordinate.latitude)!
        // 5
        self.placemarkLongitude = (placemark.location?.coordinate.longitude)!
        // 6
        let eventLatitude = self.placemarkLatitude
        // 7
        let eventLongitude = self.placemarkLongitude
        // and so on...
    }
}))

One more thing. Often, when people ask about this sort of situation on Stack Overflow, I see them use phrases like “How do I wait for the asynchronous code to finish?” This programmer, asking about the problem, says he wants to wait for self.placemarkLatitude and self.placemarkLongitude to be set before using them. But you see from the example that that’s the wrong way to look at things. You do not “wait”. Instead, you rearrange your code so that things happen in the right order, no matter when they happen.

Cool! But there’s a variant on this problem that’s even trickier: what we actually want to return a value from the asynchronous code? That’s what we’ll talk about next.