Tuesday, 27 October 2009

Changing the Annotation on the Current Location

The MKMapKit class comes with a property you can set to show the current location of the iPhone:

mapView.showCurrentLocation = YES;

This will show the little blue bubble on the map view and have the radar effect like Google Maps. However when the user touches the bubble it'll just show the text "Current Location". To set it to something other then this you can use:

mapView.userLocation.title = @"a different annotation title";

To set it to the address of that location you need to use the MKReverseGeocoder class, which is also found in the MapKit framework. You'll need to provide this delegate method in your viewController class:


- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation


This gets called whenever the location changes. Within this method you can then call the Reverse Geocoder service using:

/* warning! use this sparingly */

MKReverseGeocoder *geocoder = [[MKReverseGeocoder alloc initWithCoordinate:newLocation.coordinate];

geocoder.delegate = self;

[geocoder start];


Next declare two more methods.

-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error

{

[geocoder release];

}


-(void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark

{

[geocoder release];

mapView.userLocation.title = placemark.title;

}


The last line of code will update the title of the bubble with the correct location.

Now for the important bit. The reverseGeocoder is making a call to a Google Web service and using the latitude and longitude you provide it will return a street address or place name. If you call this function everytime the user location changes then you'll be generating a huge amount of unnecessary network traffic from and to the iPhone and putting strain on the google servers to handle your constant address requests. To minimise this I would suggest you use one of two approaches. Either keep a instance variable to keep track of the distance travelled since the last time you requested a reverseGeocoder location and only start the reverseGeocoder when a certain limit has been reached (i.e. 50 meters). You can use the CLLocation method getDistanceFrom to find this distance. Or, you could declare a NSTimer then calls starts the reverseGeocoder only after a certain interval has passed, 10 seconds for example.

Best of luck implementing this.

Timetable NZ

Next off the assembly line from the eLounge App development factory comes Timetable NZ!

I'm not going to wrote another blurb about this App as when you're publishing an App on the App Store you tend to get a little tired of writing promotional material, but if you're interested please take a look at www.elounge.net.nz. This App has been a few months of part time work in the making with some great support from the kind people of the Greater Wellington City Council and Metlink.

One thing I noticed whilst developing it was how google and the internet has completely changed software development. Whenever I came across a curly problem with the iPhone SDK, X-Code or Cocoa Touch my first port of call wasn't to try and think of a solution - it was to google the problem and try and find a code sample to get me started. Naturally I couldn't make a one to one copy and paste but I hasn't once failed to help me overcome a problem far faster then I ever would have had I been required to figure it out myself.

It's highlighted the importance to me of having developers like myself post solutions wherever possible on the internet. This is something I haven't been particularly diligent about but I'll try and make more posts in the future.