Forward Geocoding in iOS4 and iOS5

Forward Geocoding

It is a common scenario that every developer has run into.

Locate places near me based upon a particular address and/or zip code.

In order to get the correct results the address needs to be converted to a lat/long coordinate. With iOS5 Apple has provided us with CLGeoCoder class which has convience methods for reverse/forward geocoding. Unfortunately, there isn’t really any built-in functionality for iOS4. Most current apps still have to support iOS4 so what are developers doing to fill the gap? Write their implementations for multiple OS support. Below is what I use.

** Note: I did use Sergio Martínez-Losa Del Rincón article as a starting point for the iOS4 support.

Techniques

  • Google’s Map API
  • CLGeoCoder
  • Objective-C blocks for callback
  • Grand Central Dispatch

Implementation

iOS5

I tackled the easiest solution first. Utilizing iOS5’s CLGeoCoding geocodeAddressString:completionHandler: . However, when I first use the method I kept getting back a location of {0.0,0.0} in my log. The reason being that I was neglecting the fact that the method executes asynchronously and doesn’t return its value. Hmmm….

Not too much of a hurdle thanks to the implementation of block handling. By adding a completionHandler to my own method I was able to provide a callback with the appropriate coordinate that I need after the request had finished.

iOS4

Duplicating the ease of the iOS5 functionality was a bit more involved. I created a category method on NSString (see the above referenced article for code origin. I did make updates to it.) for making a call to the Google Maps API and return their forward coding result. The method itself isn’t asynchronous because I wanted to leave the decision of whether or not to call the method async or sync up to the developer. To provide asynchrous support was easy just by utiliizing GCD.

Decision Time

Deciding which code block should the calling method execute was the final task to finish. Once again this was extremely simple.

if (NSClassFromString(@“CLGeocoder”)) { // ios5 } else { // everything else. in this case we are assuming there isn’t support for iOS3.x }

Code

Creating a Universal iOS App Tutorial

Just when I thought I had a somewhat decent grasp on developing and deploying iOS apps Apple came out with the iPad and threw a whole new element in the mix when it comes to developing.  Thankfully, the iPad will allow iPhone apps to run on the device, but the user experience is definitely sub-par.  So what is the best approach to providing an native iPhone app and a native iPad app?  The first option is to duplicate your existing iPhone app code base and modify all your views and some of the controllers to take advantage of the features in the 3.2 SDK.  The problem with that is the massive DUPLICATION of code and to be honest it seems quite lazy.  I have seen lots of examples where developers use the idiom check for which device is being used, as well as, runtime checks for selectors in order to leverage the correct methods/classes for the given device.  While this is certainly a better approach then having two separate code bases with 90% of the same code you now have code that is sprinkled/littered with if/else checks.  Unfortunately, you are once again stuck with code that will be maintainable for long.  After reading the chapter on universal apps from the upcoming book from Pragmatic Programmers, iPad Programming, I found a much better design pattern of splitting out the app into Shared, iPhone and iPad resources, classes and delegates.

As a side note, due to the ever exponential growth of iOS device popularity developers are not going to have the bonus of just jumping straight into writing an app like we did when there was just the iPhone.  A lot more thought needs to be given to design patterns (especially regards to the quality of your MVC) and application flow.

In order to make life a little easier on myself since a few universal apps are coming in my near future I decided to create a basic "template" for a universal app.

Features
  • Compiled for 3.2 and 4.0
  • Utilizes navigation controller based app for iPhone device and SplitViewController for iPad
  • Shared "model" class and controller classes
  • Separate resources (classes/xibs) for the different devices

Comments and improvements are ALWAYS welcome.  One improvement that I know I want to make is having the "detail" controller from the SplitViewController to be a UINavigationController.