When showing the user's current location, there are a few ways to go about it. If you simply want the MapView instance to take care of it, you can set "showsUserLocation" to true and the MapView instance will use the GPS hardware to locate your position and place the familiar blue dot with the accuracy circle around it on the map. However, if you want to zoom in on that position, it's up to you to manage.
If you want more control or if you're placing a custom "placemark" (pushpin, etc.) onto the map, there are two main ways of doing it. The easiest and most often quoted method in tutorials involves the use of the MKReverseGeocoder library. What this does is allow you create an instance of the MKReverseGeocoder class and initialize it with a CLLocationCoordinate2D object. You then assign a delegate and then tell the MKReverseGeocoder instance to start via its start method.
The two delegate methods you're interested in when dealing with the MKReverseGeocoder library are:
-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)errorand
-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemarkWhat MKReverseGeocoder does is take a given location object (containing geocoordinate information in the form of latitude and longitude) and make a call to Google's API using an HTTP POST in order to determine what the closest address is. If the lookup is successful, didFindPlacemark: is called, but if it's note, didFailWithError: is called.
When I initially started development on this application, I never saw didFailWithError: being called for locations I gave to the MKReverseGeocoder instance. However, about a few weeks ago, I started noticing that I was consistently getting didFailWithError: ONLY after 5PM PST. A coordinate that successfully resolved to an address during the day mysteriously stopped resolving after 5PM PST. The error that was being returned was:
PBRequesterErrorDomain error 6001While this isn't very descriptive, I did a bit of searching online (using Google ironically) and found that a few other developers have started to see this behavior recently as well.
What turns out to be happening is that the HTTP POST that is being done by the MKReverseGeocoder library to Google's servers is being met with a 503 Service Unavailable error at certain times of the day (for me it's consistently between 5PM and around 9AM PST).
I have verified this by capturing the packets when using either the iPhone simulator or my iPhone while on my local WiFi network or on 3G. The following reconstruction of the packets in question:
POST /glm/mmap HTTP/1.1As you can see, what MKReverseGeocoder is actually doing is making an HTTP POST call to http://google.com/glm/mmap.
User-Agent: Apple iPhone v7D11 Maps v3.1.2
Accept-Encoding: gzip, deflate
.. ............HTTP/1.1 200 OK
Date: Mon, 28 Dec 2009 02:51:50 GMT
Expires: Mon, 28 Dec 2009 02:51:50 GMT
Cache-Control: private, max-age=0
.359.POST /glm/mmap HTTP/1.1
User-Agent: MyApp/1.0 CFNetwork/459 Darwin/9.8.0
Accept-Encoding: gzip, deflate
...... .HTTP/1.1 503 Service Unavailable
Content-Type: text/html; charset=UTF-8
Date: Mon, 28 Dec 2009 02:51:54 GMT
Expires: Mon, 28 Dec 2009 02:51:54 GMT
Cache-Control: private, max-age=0
Now I want to add that I am definitely not hitting some limit on the number of requests that I can be making since I have gone more than a day without testing this and then waited until the evening to make my first request which then failed, but in the morning after, it did not fail.
Now if Google is selectively turning off the web service that MKReverseGeocoder is relying on internally during a specific time period each day, it is something you definitely want to be aware of when using MKReverseGeocoder. Why they might be doing this is anyone's guess. In the meantime, I have submitted a bug report to Apple to see what they say. I have also made supporting posts on both Apple's private developer forum and public message boards where this behavior is also being seen, one of which includes:
http://www.iphonedevsdk.com/forum/iphone-sdk-development/31883-pbrequestererrordomain-errors-reverse-geocoding.html#post155793I have also verified that other iPhone applications already in the App Store are also exhibiting this behavior. If you download and install the "Gowalla" application, you will see that they are relying on the MKReverseGeocoder library to resolve your current location's address in their gold GPS bar at the bottom of the screen. During the times of 5PM - 9AM PST, I am noticing that it is "stuck" saying "Finding address...". At other times it is successfully resolving the address of your current location as found by the GPS.
What can you do in the meantime? There is another way to place placemarks on the map if you have a geolocation coordinate that doesn't involve the use of MKReverseGeocoder but instead uses the addAnnotation method in the MapView class:
- (void)addAnnotation:(idIn order to create an annotation object to be added to the map, you'll want to create a MapAnnotation class that inherits from MKAnnotation. The members of this class should include:
CLLocationCoordinate2D coordinate;where annotationType is an enumeration where you can customize different placemark graphics for different types.
You also need to define a method with which to use during the object's initialization:
-initWithCoordinate:(CLLocationCoordinate2D)inCoord;All you then need to do is instantiate your MapAnnotation class, passing the geocoordinate where you want the placemark to appear on the map. Then add this instance to your MapView instance via the MapView's addAnnotation method. The MKMapViewDelegate methods that you should be listening to in the class that you're using for all of this will then message the following method:
-(MKAnnotationView *)mapView:(MKMapView *)mapView viewForAnnotation:(idAt this point, you can check the annotation type to show custom placemark graphics, or you could just place a generic color pin, etc. Either way, you will need to return an instance of the MKAnnotationView class for your placemark to appear on the map.
Unfortunately, if you have a geocoordinate and absolutely need to display the address but don't know what it is, if you're relying on the Google functionality that is used by the MapKit library, I'm not sure what you can do at the moment. There are other alternatives to using MapKit that I won't go into here but beware of using MapKit if you're depending on resolving a physical address given a geocoordinate.
Any input is welcome and I will update this post with any updates that I may find in the future.
"edpark" on the iPhone dev SDK forum makes a good point:
Here's my theory. We know that Google throttles reverse-geocoding requests by IP. My suspicion is that this throttling is reset at midnight each night and that MKReverseGeocoder passes its requests through a centralized caching proxy; since that proxy would appear as a single IP to Google, it stops working at a certain point during the day.