The usual way to develop apps for iOS, the operating system used on Apple's iPhone and iPad devices, is by means of XCode, a free development environment which runs on Mac OS. We provide an iOS framework for CartoType. It allows you to use both Swift and Objective C to create CartoType apps.

A simple test app

You can download the source code of a simple test app which uses the CartoType evaluation library.

First get the test project source files for either Swift or Objective C.

Open the project in Xcode on a Macintosh.

Add the CartoType evaluation framework to the project.

Add the map, style sheet and font to the project.

You can then run it in the simulator or on an iOS device. The CartoType evaluation library is built for, and works on, both the 32-bit (Arm7) and 64-bit (Arm64) iOS environments.

The code is largely self-explanatory. It loads and displays a map, and allows the user to pan, zoom and rotate the map using gestures. You can create a route by clicking successively on two points It is designed as a minimal app, and therefore is deliberately very simple.

Using CartoType with tile-based SDKs

You can use various tile-based SDKs with CartoType. They provide the application front-end, including the user interaction, and you create a tile provider to draw tiles as required. These SDKs always work with the Web Mercator projection, so you'll need to create maps using /project=m with our generate_map_data_type1 tool.

Threading issues

In general, tile-based SDKs such as Map Kit, Mapbox and the Google Maps SDK create extra threads to handle tile requests. CartoType is not thread-safe, so you need to do two things to avoid crashes:

1. Put the call to CartoType to get the tile bitmap inside a @synchronized block, synchronizing on the CartoTypeFramework object ('cartotype_framework' in this example):

@synchronized(cartotype_framework) { image_ref = [cartotype_framework getTileBitmapWithSize:256 andZoom:zoom andX:x andY:y]; }

2. Put all calls to CartoType functions which could possibly be executed during tile creation inside a @synchronized block, synchronizing on the same framework object. For example, when creating a route:

@synchronized(cartotype_framework)
   {
   result = [cartotype_framework startNavigationFrom:start_point startCoordType:DegreeCoordType to:end_point endCoordType:DegreeCoordType];
   }

Note that this procedure is not necessary when using CartoType's own tile source system.

Use the Google Maps SDK with CartoType

Here's how to use the Google Maps SDK and draw tiles using CartoType as a custom tile layer. It works extremely well, giving a fast, fluid user experience; it also supports rotation. It's your responsibility to verify that the Google Maps SDK license is compatible with your intended use, whether commercial or non-commercial.

You create an implementation of GMSSyncTileLayer (https://developers.google.com/maps/documentation/ios/reference/interface_g_m_s_sync_tile_layer), like this ('carto' is a pointer to a CartoTypeFramework object, as defined in the CartoType iOS API):

#import "MyCustomTileLayer.h"
@implementation MyCustomTileLayer
- (id)init
{
 NSLog(@"INIT");
 carto = [[CartoTypeFramework alloc] initWithMap:@"santa-cruz-mercator" andStyle:@"osm-style" andFont:@"DejaVuSans" andWidth:400 andHeight:400];
 return self;
}
- (UIImage *)tileForX:(NSUInteger)x y:(NSUInteger)y zoom:(NSUInteger)zoom {
 NSLog(@"%s x: %d y: %d, z: %d", __FUNCTION__, x, y, zoom);
UIImage *img;
@synchronized(carto)
 {
 CGImageRef imgRef = [carto getTileBitmapWithSize:256 andZoom:zoom andX:x andY:y];
 img = [UIImage imageWithCGImage:imgRef];
 NSLog(@"%@";, img);
 }
 return img;
}
@end

and in your view controller, you can do this:

- (void)viewDidLoad
{
 [super viewDidLoad];
GMSCameraPosition *camera = [GMSCameraPosition cameraWithLatitude:36.974117
 longitude:-122.030796
 zoom:16];
 mapView = [GMSMapView mapWithFrame:CGRectZero camera:camera];
 mapView.delegate = self;
 mapView.mapType = kGMSTypeNone;
 mapView.myLocationEnabled = YES;
 self.view = mapView;
 
 MyCustomTileLayer *customTileLayer = [MyCustomTileLayer new];
 customTileLayer.map = mapView;
 
}

Using the Mapbox SDK with CartoType

Here's how to use the Mapbox SDK on iOS, using CartoType as a custom tile layer. It's your responsibility to verify that the Mapbox SDK license is compatible with your intended use, whether commercial or non-commercial.

view-controller implementation

#import "CartoTypeViewController.h"
#import "MapBox.h"
#import "CartoTypeTileSource.h"
@implementation CartoTypeViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
 self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
 if (self) {
 // Custom initialization
 }
 return self;
}
- (void)viewDidLoad
{
 [super viewDidLoad];
 // Do any additional setup after loading the view. 'sample-map.ctm1' is the CartoType map file; osm-style.xml is the style sheet; DejaVuSans.ttf is the font
 CartoTypeTileSource *s =[[CartoTypeTileSource alloc]initWithMap:@"sample-map" style:@"osm-style" font:@"DejaVuSans"];
 
 RMMapView *mapView = [[RMMapView alloc]initWithFrame:self.view.bounds andTilesource:s];
 mapView.autoresizesSubviews = UIViewAutoresizingFlexibleWidth|UIViewAutoresizingFlexibleHeight;
 mapView.debugTiles = YES;
 [self.view addSubview:mapView];
 
 float minlon = -2;
 float minlat = 49;
 float maxlon = 2;
 float maxlat = 51;
 
 [mapView zoomWithLatitudeLongitudeBoundsSouthWest:CLLocationCoordinate2DMake(minlat, maxlon) northEast:CLLocationCoordinate2DMake(maxlat, minlon) animated:NO];
 
}
- (void)didReceiveMemoryWarning
{
 [super didReceiveMemoryWarning];
 // Dispose of any resources that can be recreated.
}
- (void)viewDidAppear:(BOOL)animated {
 
}

CartoType tile source interface

#import "MapBox.h"
#import <CartoType/CartoType.h>
@interface CartoTypeTileSource : RMAbstractMercatorTileSource
@property (nonatomic,strong)CartoTypeFramework *framework;
-(id)initWithMap:(NSString*)fileName style:(NSString*)styleSheetFileName font:(NSString*)fontFileName;
@end

CartoType tile source implementation


#import "CartoTypeTileSource.h"
@implementation CartoTypeTileSource
- (id)init {
 self = [self initWithMap:nil style:nil font:nil];
 return self;
}
-(id)initWithMap:(NSString*)fileName style:(NSString*)styleSheetFileName font:(NSString*)fontFileName {
 self = [super init];
 if(self) {
 int size = 256;
 self.framework = [[CartoTypeFramework alloc]initWithMap:fileName andStyle:styleSheetFileName andFont:fontFileName andWidth:size andHeight:size];
 self.cacheable = NO;
 }
 return self;
}
- (UIImage *)imageForTile:(RMTile)tile inCache:(RMTileCache *)tileCache {
 CGImageRef tileCGImage = NULL;
 @synchronized(self.framework) {
 tileCGImage = [self.framework getTileBitmapWithSize:256 andZoom:tile.zoom andX:tile.x andY:tile.y];
 CGImageRetain(tileCGImage);
 UIImage *tileImage = [UIImage imageWithCGImage:tileCGImage];
 CGImageRelease(tileCGImage);
 }
 return tileImage;
}
- (NSString *)uniqueTilecacheKey {
 return @"CartoTypeTileSource";
}
- (NSString *)shortName {
 return @"CartoType tile source";
}

- (NSString *)shortAttribution {
 return @"CartoType";
}
@end

Find out more

If you'd like to find out more about using CartoType on iOS, please use the form or e-mail address on the contact page.