Apple introduced the Swift programming language in 2014. It has now largely replaced Objective C to become the language of choice for iOS applications. However, CartoType's iOS API is written in Objective C. This article explains how to use the CartoType iOS SDK in a Swift project. You can use CartoType completely from Swift. There is no need to write any Objective C.

Create a Swift project

You'll need to install Xcode 7 on your Macintosh. All versions of Xcode from version 6 onwards support Swift; the following example was created using Xcode 7. Create a project in the normal way, and choose Swift as the language.

Add the CartoType framework to the project

Download the latest evaluation SDK. Double-click on the .dmg file containing the CartoType framework, which mounts the .dmg file as a drive. Drag the file CartoType.framework into your project, and, when prompted, choose to copy the files.

Create a bridging header

You need to create a header file to import all the Objective C headers you need. This is very easy. In Xcode, add a new Objective C file to your file (call it anything you like) and when Xcode asks whether you want to create a bridging header, say yes. Xcode will create a file called <project-name>-Bridging-Header.h, with nothing but some comments at the top. After the comments, insert this text:

#import <CartoType/CartoType.h>

That's everything you need to do to make CartoType available to your Swift code!

What the CartoType API looks like in Swift

Xcode automatically translates the CartoType Objective C API into Swift. For example, the init function for CartoTypeFramework changes from this Objective C declaration

-(id)initWithParam:(CartoTypeFrameworkParam*)aParam;

to this Swift version

public init!(param aParam: CartoTypeFrameworkParam!)

and the setView function, which is declared like this in Objective C

-(CTResult)setView:(CartoTypeRect)aView coordType:(CartoTypeCoordType)aCoordType margin:(int)aMarginInPixels minScale:(int)aMinScaleDenominator;

becomes

public func setView(aView: CartoTypeRect, coordType aCoordType: CartoTypeCoordType, margin aMarginInPixels: Int32, minScale aMinScaleDenominator: Int32) -> CTResult

If you want to examine the Swift version of the API, it's very easy in Xcode. Open one of the CartoType framework headers in the Xcode editor, for example CartoTypeFramework.h, which is the main one. Click on the intersecting-circles icon in the top right corner to open the 'assistant editor' pane. At the top, select Counterparts->CartoTypeFramework.h (Interface). You should see the whole header file, converted into Swfit: this is the interface that's available to you in your Swift code.

Sample code

You can view and download sample code for a simple demonstration of CartoType using Swift.

The CartoTypeDemoView class in CartoTypeDemoView.swift draws a map using hardware graphics acceleration.

The ViewController class in ViewController.swift adds buttons for starting and ending navigation and insserting and deleting pushpins, and handles gestures to pan, zoom and rotate the map.

//
// CartoTypeDemoView.swift
// CartoTypeSwiftDemo
//
// Created by Graham Asher on 21/11/2016.
// Copyright © 2016-2018 CartoType Ltd. All rights reserved.
//
import UIKit
import GLKit

/** A view class for drawing maps using graphics acceleration. */
class CartoTypeDemoView : GLKView
{
var m_framework : CartoTypeFramework?
var m_map_renderer : CartoTypeMapRenderer?

override init(frame aFrame: CGRect)
{
let opengl_context = EAGLContext.init(api: EAGLRenderingAPI.openGLES2)
super.init(frame: aFrame, context:opengl_context!);
self.drawableDepthFormat = GLKViewDrawableDepthFormat.format24 // so that 3D buildings work
}

required init?(coder aDecoder: NSCoder)
{
super.init(coder: aDecoder)
self.context = EAGLContext.init(api: EAGLRenderingAPI.openGLES2)
self.drawableDepthFormat = GLKViewDrawableDepthFormat.format24 // so that 3D buildings work
}

func setFramework(_ aFramework: CartoTypeFramework!)
{
m_framework = aFramework
m_map_renderer = nil;
}

override func draw(_ rect: CGRect)
{
if (m_map_renderer == nil && m_framework != nil)
{
m_map_renderer = CartoTypeMapRenderer.init(_: m_framework)
}

if (m_map_renderer != nil)
{
m_map_renderer!.draw();
}
}
}