Skip to main content

Public Transit Route Instructions

Last updated: April 7, 2026 | 2 minutes read

This example demonstrates how to use GEMKit in a UIKit application to calculate a public transit route and display a detailed step-by-step breakdown of each transit segment, including departure times, line colours, and walking legs.

Check the full implementation on GitHub.

Public Transit Route Instructions

UI and Map Integration

The view controller calculates the route and stores the first result. A list-button in the navigation bar launches the instructions screen:

ViewController.swiftView on GitHub
class ViewController: UIViewController, UISearchBarDelegate {

var mapViewController: MapViewController?
var navigationContext: NavigationContext?
var mainRoute: RouteObject?

override func viewDidLoad() {
super.viewDidLoad()

self.title = "Public Transit"
self.navigationItem.largeTitleDisplayMode = .never

self.createMapView()
self.mapViewController!.startRender()
self.addRouteButton()
}

@objc func routeDescription(item: UIBarButtonItem) {

if let route = self.mainRoute {

let viewController = PTRouteDescriptionViewController.init(route: route)
self.navigationController?.pushViewController(viewController, animated: true)
}
}

Building the Instructions Model

PTRouteDescriptionViewController iterates the route's segments, casting each to PTRouteSegmentObject to access transit-specific properties such as departure time and line colour. Walking legs are handled separately:

PTRouteDescriptionViewController.swiftView on GitHub
func prepareModelData() {

guard self.route != nil else { return }

let segmentList = self.route!.getSegments()

for segment in segmentList {

guard let segmentPT = segment as? PTRouteSegmentObject else { continue }
guard segmentPT.isSignificant() else { continue }

let section = ModelDataSection.init()
section.area = segment.getGeographicArea()

if segment.isCommon() {

let t1 = segmentPT.getDepartureTimeFormatted()
let t2 = segmentPT.getDepartureTimeUnitFormatted()

let transitType = segmentPT.getTransitType()
var image = UIImage.init(systemName: "tram")

if transitType == .bus {
image = UIImage.init(systemName: "bus")
} else if transitType == .underground {
image = UIImage.init(systemName: "tram.tunnel.fill")
}

section.departureTime = "Departure: " + t1 + t2
section.image = image
section.color = segmentPT.getLineColor().withAlphaComponent(0.4)

} else {

section.image = UIImage.init(systemName: "figure.walk")

let d1 = segment.getTimeDistance()!.getTotalDistanceFormatted()
let d2 = segment.getTimeDistance()!.getTotalDistanceUnitFormatted()
let t1 = segment.getTimeDistance()!.getTotalTimeFormatted()
let t2 = segment.getTimeDistance()!.getTotalTimeUnitFormatted()

section.departureTime = d1 + d2 + " (" + t1 + t2 + ")"
}

for routeInstruction in segment.getInstructions() {

let item = ModelDataItem.init()
item.routeInstruction = routeInstruction
section.items.append(item)
}

self.modelData.append(section)
}
}