Playing With MapKit
Part 2 Reverse Geocoding and Custom Annotation Callouts
Part 4 Race Conditions, Other Bugs, and Wrap-up
As the functionality and the look was coming into place, I took note of bugs that I saw.
The most insidious bugs are ones that don’t happen all the time or under conditions (ex. when internet is especially slow or the computer is especially fast). One example is the race condition.
What is a Race Condition?
A race condition is a situation when the sequence of asynchronous responses results in an undesired effect.
My Example


Very quickly after starting the app, I was tapping the current location dot and I was seeing “Current Location” in the bubble. It should have said the address that the address was closest to. If I waited a couple seconds to tap the current location, it would display the address as expected.
This led me to believe that I had a race condition.
Under normal conditions:
- The map updates the user location calling its delegate mapView:didUpdateUserLocation: which starts the reverseGeocoding call based on the user’s location.
- The reverseGeocoding response is received and the completion block sets the annotation’s title with the address of the user location.
- When the user location dot is tapped, it will display a custom bubble using the annotation’s title in the label.
Usually the internet is fast enough that the reverseGeocoding response returns before the user location dot is tapped.
The two things that are racing are
- the reverseGeocoding network call and
- the tap of the current location dot.
If 1 finished first, then the app would work as intended. If 2 finished first, the experience would be suboptimal.
Design Choice
One way to fix this is to update the label when the reverseGeocoding network call came back.
At the end of the completion block, I added a method call to updatePinCallout, which pretends that the user location dot was tapped again and reloads the address.
- (void)updatePinCallout { if (self.userLocationPin.selected) { [[NSOperationQueue mainQueue] addOperationWithBlock:^{ [self.userLocationPin setSelected:YES animated:YES]; }]; } }
Just remember to use the mainQueue to retap the dot or else the address won’t update on screen.
This change also fixed another bug that happened when the user location would jump when WIFI was enabled and the address label would not update to the new address.
Alternative Choice
Another thing that I found solved the problem pretty well was to zoom the map to the user location immediately, so that the animation didn’t even give a chance to tap the user location dot.
Other Bugs
Writing code for multiple scenarios unnecessarily
When I first implemented zooming to fit destinations, I only zoomed when the location was outside of the visible region. I realized that sometimes this would not be sufficient because sometimes the map would be zoomed way out, so I decided to account for that scenario too. I would zoom in if the destination was in the original visible area. This got complicated quickly.
Eventually, I realized that it was too much and just made it always zoom to the destination. The code went from 14 lines to 1.
Testing Days Later
I thought I was done with the project. Wrong. A few days later, I was trying out the app on the bus and came across two bugs.


- I was on a bus and the location was updating very quickly and constantly centering the map on the new location. The problem was that I wanted to look around the map and couldn’t do that without it changing while I was using it.
- This is easily fixed by only zooming on the time the map loads.
- I was looking for a Pret A Manger. When I saw the results page, I found it utterly useless because all of them said the same thing and I couldn’t tell which location was where.
- I think it would have been cool to add some directions as to how far each location was from my current location and in which direction or add the cross streets.
As the Pragmatic Programmer said:
“Test your software, or your users will.”
Where to next?
There’s certainly a lot of ways this can go. Add friends, add Facebook integration, add Yelp results, use Google Maps. That would be fun to do, but would lack direction.
For a product to be real, it must have a real use.
The way that this app fits into my life has something to do with lunch (ergo the name LunchTime). In an effort to build good habits, one of them is to walk 10K steps a day. As I’ve discovered, this means walking 1.3 hours a day. If I don’t plan to walk, I won’t get near 10K.
So over lunch, I like to walk 10 to 15 minutes away and back. I think it would be cool to draw a diamond around your current location to see how far you can walk in 5 and 15 minutes and show how far each location is.
Options abound. Looking forward to the next expedition.
It’s been fun working with MapKit. Time to play around with something else. Who knows? I might be looking at WatchKit, EventKit, or something else entirely.