Esri's Geotrigger Service is replacing Geoloqi! Learn More | FAQ

Replacing MapKit with ArcGIS

Next Page

The ArcGIS SDK for iOS provides just as much and even more functionality as Apple's standard MapKit framework. Some of the vocabulary and terms used may be unfamiliar to those coming from the MapKit APIs. Below are some common and simple examples of the basics of replacing MapKit with ArcGIS.

Install the SDK and configure your XCode project

ESRI's ArcGIS resource center has good instructions on how to accomplish this. See these pages:

Replace MKMapView with AGSMapView

Let's say you have a standard MKMapView in your XIB, with @property and @synthesize directives for it in your interface and implementation:

Once you've installed the ArcGIS SDK for iOS and configured your project, you should have access to <ArcGIS/ArcGIS.h>:

You can then select and delete the MKMapView from your XIB, and drag in a vanilla UIView object to replace it. With the new UIView selected, change the class field in the Identity Inspector view on the Utilities sidebar to AGSMapView and wire it up to your interface:

You could build and run your application now, but this view would not show you anything. Since ArcGIS has the ability to use many different basemaps, you need to create a AGSTiledMapServiceLayer, feed it the basemap you want, and add it to the AGSMapView. For this example, I chose "World Street Map":

#define BASEMAP_URL @"http://server.arcgisonline.com/ArcGIS/rest/services/World_Street_Map/MapServer"

...

- (void)viewDidLoad
{
    ...
    NSURL *basemap = [NSURL URLWithString:BASEMAP_URL];
    [self.mapView addMapLayer:[AGSTiledMapServiceLayer tiledMapServiceLayerWithURL:basemap]
                     withName:@"Tiled Layer"];
    ...
}

Now you should be able to run this application and see an AGSMapView with tiles loading in:

Configuring AGSMapView

As you can see in the image above, we are zoomed all the way out, and the map does not wrap when you scroll. MKMapView maps don't wrap either, but this is an easy place to start:

// AGSMapView objects have a `wrapAround` property
self.mapView.wrapAround = YES;

It would also be very handy if the map started out life by showing us our immediate vicinity. This entails a few steps that can be generified as:

  • find out the device's current location in latitude and longitude
  • create a box around that location
  • zoom the map to that box

These steps are the same regardless of using MapKit or ArcGIS so let's go through each one in a bit more detail.

Getting the device's current location

CoreLocation is fantastic, albeit opaque. However, for our current purposes, it will do just fine. In this first step, this process is the same for both types of map views:

- (void)viewDidLoad
{
    [super viewDidLoad];

    // locationManager is a private instance var
    locationManager = [CLLocationManager new];
    locationManager.delegate = self;
    [locationManager startUpdatingLocation];
}

// this method is deprecated in iOS 6
- (void)locationManager:(CLLocationManager *)manager didUpdateToLocation:(CLLocation *)newLocation fromLocation:(CLLocation *)oldLocation
{
    NSMutableArray *locations = [NSMutableArray arrayWithObject:newLocation];
    if (oldLocation) [locations insertObject:oldLocation atIndex:0];
    [self locationManager:locationManager didUpdateLocations:locations];
}

- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray *)locations
{
    // most recent is last in the list
    CLLocation *location = [locations objectAtIndex:(locations.count - 1)];

    // let's wait until we get a good enough fix...
    if (location.horizontalAccuracy < 100.0) {

        CLLocationCoordinate2D latlng = location.coordinate;

        // TODO make bounding box

        // TODO tell map to zoom to it

        // got a good fix, stop updating
        [locationManager stopUpdatingLocation];
    }
}

Creating a bounding box around the location

In normal MapKit programming, you would now build up a MKCoordinateRegion data structure so that you can "zoom" the map to it. You would replace that first TODO above with something like this:

// MKCoordinateSpan values are for the whole screen...
float extentDelta = 0.05;
MKCoordinateRegion region = {latlng, (MKCoordinateSpan){extendDelta, extentDelta}};

However, in GIS terms, this is usually not called a "Coordinate Region", but instead is known as an "Extent" or "Envelope". The ArcGIS classes are named accordingly. Also, ArcGIS classes know about another term, "Spatial Reference". Discussion of different types of spatial references is beyond the scope of this document. Here is the equivalent code when using ArcGIS:

// ... while these X/Y max/min values represent corners
float extentDelta = 0.025;
AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin:(latlng.longitude - extentDelta)
                                                 ymin:(latlng.latitude -  extentDelta)
                                                 xmax:(latlng.longitude + extentDelta)
                                                 ymax:(latlng.latitude +  extentDelta)
                                     spatialReference:[AGSSpatialReference wgs84SpatialReference]];

As you can see, AGSEnvelope gives you much finer control of the "box", requiring you to set your SW and NE corners individually.

Also note that AGSEnvelope, like many things in ArcGIS SDK for iOS, uses x and y terminology instead of latitude and longitude. It is important to realize that x corresponds to longitude and y corresponds to latitude. This may seem backwards at first, but it does makes sense.

"Zooming" the map to the bounding box

With an MKCoordinateRegion in hand, we can tell MKMapView to show it very easily. You could replace the second TODO above with:

[self.mapView setRegion:region animated:YES];

It is equally easy to acheive the same result with AGSMapView:

[self.mapView zoomToEnvelope:envelope animated:YES];

Here are comparison screenshots, MapKit on the left, and ArcGIS Maps on the right.

Apple MapKit ArcGIS Maps

Next Page