Tuesday, August 18, 2009

[iPhone MapKit] Controlling a MKMapView added in Interface Builderapp

Way back in December of 2008 I started dreaming about what kind of app I'd like to try and create for the iPhone, and ultimately I came down to something that would fit my love of travel and photography. And one of the areas that has given me quite a bit of a headache was around how to integrate a map with my app.

What was the sticking point? Well, it had to do with my desire to include some sort of mapping data, or better yet a map, in the app itself. Back in December, this was a huge task, and much larger than I had ever thought. At the time the MapKit didn't exist, so you were left with trying to do a huge amount of work in force fitting some other map technology into a view. Granted, many people have done that, and there are some great apps out there that do exactly that, in fact I use one myself (WeatherBug) which uses Microsoft's Virtual Earth.

About half way through my process of working on getting some sort of map integrated with my app, Apple comes out and announces the 3.0 SDK, which included an API to the mapping application, conveniently called MapKit. During the beta time, not many people had used MapKit, and initially it was all hard coded code. In fact, there's a great tutorial on this at the objectgraph.blog that I highly recommend.

Using the Interface Builder MKMapView Object
When using the objectgraph.blog tutorial, you'll probably notice that he's adding the map programatically. This is due to the fact that the early SDK betas did not include an Interface Builder object. So you had to create your MKMapView via code, then add it to a view to display.

Well, I didn't really want my map to take up the whole view, I'd rather have it be a smaller part of my overall view, so the IB object works great as I can visually size the map on my screen.

So I went into IB and designed this layout:

Then hopping back over to XCode, I attempted to wire it up so that I could control it. This proved to be a much larger headache that I had thought. Using the examples I had found I started by declaring a MapView in my interface code:

MKMapView *mapView;

...
...

@property (nonatomic, retain) IBOutlet MKMapView *mapView;


Then in my implementation code I tried to connect to the map view by doing this:

- (void)viewDidLoad {

mapView = [[MKMapView alloc] init];


Which if you try, you'll quickly learn, this doesn't work...

After going over all the examples I could find, and realizing eventually that all these folks were using the MapKit before IB had an object, I finally figured out what the problem was.

By assigning my IBOutlet to a new allocated object, I effectively broke my connection to the map. Since I declared this as a property and @synthesize it, that work was being done for me, and I could just start using it right away.

Here's my final viewDidLoad method which sets a few options for the map, and also configures some of the other parts as well...

- (void)viewDidLoad {

// set the current location lable to blank strings (will be populated later...)

currentLocationLabel.text = @"";

currentHeightLabel.text = @"";

reverseGeocodeLabel.text = @"";

// setup the mapView options

[mapView setMapType:MKMapTypeSatellite];

[mapView setZoomEnabled:YES];

[mapView setScrollEnabled:YES];

// initalize the location manager

self.locationManager = [[CLLocationManager alloc] init];

locationManager.delegate = self;

locationManager.desiredAccuracy = kCLLocationAccuracyBest;

[super viewDidLoad];

}

And finally, the running app with a working map:

No comments:

Post a Comment