A rather nifty new feature of the iPhone SDK is the ability to reverse geocode a location. Some of you may be wondering what normal geocoding is! Well, geocoding is turning an address into a latitude and longitude. So reverse geocoding is, without surprise, turning a latitude and longitude into an address.
So, in combination with the normal iPhone lookup services, you can find out the lat,long of someone and then convert that into a friendly place name such as the town they are in. It’s very easy to do, firstly you need to implement the MKReverseGeocoderDelegate protocol in your chosen class which has two callbacks, one for when a reverse geocode is successful and one for when there is an error:
- (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFindPlacemark:(MKPlacemark *)placemark; - (void)reverseGeocoder:(MKReverseGeocoder *)geocoder didFailWithError:(NSError *)error;
So we create and initialise a reverse Geocoder with the following code. Note the delegate is set to self so the methods defined above should be places in the same class. locationToLookup defines where the location name we want to look up is (as a latitude, longitude coordinate).
// use whatever lat / long values or CLLocationCoordinate2D you like here. CLLocationCoordinate2D locationToLookup = {52.0,0}; MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:locationToLookup]; reverseGeocoder.delegate = self; [reverseGeocoder start];
The first time I tried this I got the very cryptic error message below:
Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '*** -[LBSGAddressComponent _mapkit_cache_heapTime]: unrecognized selector sent to instance 0x166c00'
After a lot of head scratching I realised this is because you must only ever have one reverse geocoder running at once. So I made the reverse geocoder a class variable (to keep track of it) and added:
if (reverseGeocoder != nil) { // release the existing reverse geocoder to stop it running [reverseGeocoder release]; } // use whatever lat / long values or CLLocationCoordinate2D you like here. CLLocationCoordinate2D locationToLookup = {52.0,0}; MKReverseGeocoder *reverseGeocoder = [[MKReverseGeocoder alloc] initWithCoordinate:locationToLookup]; reverseGeocoder.delegate = self; [reverseGeocoder start];
This will stop any existing lookups. And so if successful your callback method will be called with an instance of MKPlacemark that represents where your lookup is. Easy.
Comment spammers scum, WordPress and re-CAPTCHA
The spam comments on this site were progressively getting worse and worse. It’s a ridiculous situation since all comments are only show after approval so not a single one was ever being shown on the site. But it still takes time to monitor and becomes more annoying as time goes on. This morning I had already had 10 and so decided enough is enough.
I installed the very excellent re-CAPTCHA. This captcha software is a bit different for several reasons. Firstly it has a WordPress plugin which took 5s to install. Secondly it helps organisations digitise books, a very honourable motive. To install you just need to:
So how does re-CAPTCHA work then? Captchas rely on testing if you are human by quizzing you on something that should be easy for a human and relatively hard for a computer to solve. OCR, i.e. recognising the image of a word as text can be extremely hard for computers if the page is distorted, grainy or badly printed. So re-CAPTCHA asks you to OCR two words. Why two? Well one is already known since it has been confirmed by other users (how else would re-CAPTCHA know your answer was correct), the other is not known and so you are providing a useful service helping a document be recognised (and providing new captcha answers for other users). Simple but ingenius.