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

ArcGIS maps for iOS

The ArcGIS SDK for iOS provides an alternative to using Apple's MapKit.

ArcGIS maps for iOS Diagram

ArcGIS SDK for iOS

Looking for another option for iOS maps? Try the ArcGIS maps for iOS. Some of features available include:

  • Use any tile service that ArcGIS supports (including Bing)
  • Add layers from any ArcGIS feature service
  • Use tasks for common uses like geocoding/locating, routing/directions, and querying
  • Enable collabartion via WebMaps

We have a more detailed discussion over here and a quick sample below.

Sample Code

This will put a call out on a Bing aerial map with labels. The first class, LQPortlandAnnotation serves as a data model for both MKAnnotation purposes (which aren't needed here) and an AGSInfoTemplateDelegate for AGSGraphic.

LQPortlandAnnotation.h:

#import <UIKit/UIKit.h>
#import <MapKit/MapKit.h>
#import <ArcGIS/ArcGIS.h>

@interface LQPortlandAnnotation : NSObject <MKAnnotation, AGSInfoTemplateDelegate>
@end

LQPortlandAnnotation.m:

#import "LQPortlandAnnotation.h"

@implementation LQPortlandAnnotation

@synthesize coordinate, title, subtitle;

- (LQPortlandAnnotation *)init
{
    self = [super init];
    if (self) {
        coordinate = (CLLocationCoordinate2D){ 45.5236, -122.6750 };
        title = @"Portland!";
        subtitle = @"Yee haw!!!";
    }
    return self;
}

// convert instance variable from `CLLocationCoordinate2D`, which takes doubles
// of degrees for latitude and longitude, to `AGSPoint` in the "Web Mercator"
// spatial reference.
//
- (AGSPoint *)webMercatorPoint
{
    AGSPoint *p = [AGSPoint pointWithX:self.coordinate.longitude
                                     y:self.coordinate.latitude
                      spatialReference:[AGSSpatialReference wgs84SpatialReference]];
    p = (AGSPoint *)[[AGSGeometryEngine defaultGeometryEngine] projectGeometry:p
                                                            toSpatialReference:[AGSSpatialReference webMercatorSpatialReference]];
    return p;
}

// returns the same data as the `MKAnnotation` property
//
- (NSString *)titleForGraphic:(AGSGraphic *)graphic screenPoint:(CGPoint)screen mapPoint:(AGSPoint *)map
{
    return self.title;
}

// returns the same data as the `MKAnnotation` property
//
- (NSString *)detailForGraphic:(AGSGraphic *)graphic screenPoint:(CGPoint)screen mapPoint:(AGSPoint *)map
{
    return self.subtitle;
}

@end

Here is the actual controller class. The XIB has only one view in it, AGSMapView; and it is wired to the IBOutlet below.

LQViewController.h:

#import <UIKit/UIKit.h>
#import <ArcGIS/ArcGIS.h>

@interface LQViewController : UIViewController <CLLocationManagerDelegate>
@property (strong, nonatomic) IBOutlet AGSMapView *mapView;
@end

Finally, the implementation for the view controller. This zooms to the device's location, then shows a callout over Portland, OR.

LQViewController.m:

#import "LQViewController.h"

@implementation LQViewController {
    @private
    CLLocationManager *locationManager;
    AGSLayer *baseLayer;
    LQPortlandAnnotation *pdx;
}

@synthesize mapView = _mapView;

- (void)viewDidLoad
{
    [super viewDidLoad];
    pdx = [LQPortlandAnnotation new];

    baseLayer = [[AGSBingMapLayer alloc] initWithAppID:@"basemap" style:AGSBingMapLayerStyleAerialWithLabels];
    [self.mapView addMapLayer:baseLayer withName:@"Basemap"];
    self.mapView.wrapAround = YES;

    locationManager = [CLLocationManager new];
    locationManager.delegate = self;
    locationManager.desiredAccuracy = kCLLocationAccuracyBestForNavigation;
    [locationManager startUpdatingLocation];
}

#pragma mark -

- (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
{
    CLLocation *location = [locations objectAtIndex:(locations.count - 1)];

    if (location.horizontalAccuracy < 100.0) {
        [self setExtent:location withDelta:0.025 animated:YES];
        [locationManager stopUpdatingLocation];
        [self createCallout];
    }
}

- (void)setExtent:(CLLocation *)location withDelta:(float)delta animated:(BOOL)animated
{
    CLLocationCoordinate2D latlng = location.coordinate;
    AGSEnvelope *envelope = [AGSEnvelope envelopeWithXmin:(latlng.longitude - delta)
                                                     ymin:(latlng.latitude - delta)
                                                     xmax:(latlng.longitude + delta)
                                                     ymax:(latlng.latitude + delta)
                                         spatialReference:[AGSSpatialReference wgs84SpatialReference]];
    [self.mapView zoomToEnvelope:envelope animated:animated];
}

#pragma mark -

- (void)createCallout
{
    static NSString *graphicsLayerKey = @"graphicsLayer";

    id<AGSLayerView> lv = [self.mapView.mapLayerViews objectForKey:graphicsLayerKey];
    AGSGraphicsLayer *graphicsLayer = (AGSGraphicsLayer *)lv.agsLayer;
    if (!graphicsLayer) {
        graphicsLayer = [AGSGraphicsLayer graphicsLayer];
        [self.mapView addMapLayer:graphicsLayer withName:graphicsLayerKey];
    }

    AGSGraphic *dot = [AGSGraphic graphicWithGeometry:[pdx webMercatorPoint]
                                               symbol:[AGSSimpleMarkerSymbol simpleMarkerSymbolWithColor:[UIColor blueColor]]
                                           attributes:nil
                                 infoTemplateDelegate:pdx];

    [graphicsLayer addGraphic:dot];
    [graphicsLayer dataChanged];
}

#pragma mark -

- (void)didReceiveMemoryWarning
{
    [super didReceiveMemoryWarning];
    // Dispose of any resources that can be recreated.
}

- (void)viewDidUnload {
    [self setMapView:nil];
    [super viewDidUnload];
}

@end