Skip to main content

Positions

Last updated: March 18, 2026 | 7 minutes read

This page covers position handling in iOS using PositionObject and PositionContext.

Tip

Do not confuse CoordinatesObject with PositionObject.

CoordinatesObject describes a location only. PositionObject includes movement and quality metadata such as speed, course, provider, and map-matching context.

Create and access positions

In most app flows, you receive positions from PositionContext. For testing and simulation-style pipelines, you can also create a PositionObject manually with createPosition:latitude:longitude:altitude:course:speed:speedAccuracy:horizontalAccuracy:verticalAccuracy:courseAccuracy:.

let synthetic = PositionObject.createPosition(
Date().timeIntervalSince1970 * 1000,
latitude: 48.858844,
longitude: 2.294351,
altitude: 35.0,
course: 90.0,
speed: 13.5,
speedAccuracy: 1.2,
horizontalAccuracy: 5.0,
verticalAccuracy: 8.0,
courseAccuracy: 10.0
)

Start continuous updates

Use PositionContext to receive continuous updates:

final class PositionHandler: NSObject, PositionContextDelegate {
private let positionContext: PositionContext

init(dataSourceContext: DataSourceContext) {
self.positionContext = PositionContext(context: dataSourceContext)
super.init()
self.positionContext.delegate = self
}

func startRawUpdates() {
positionContext.startUpdatingPositionDelegate(.position)
}

func startImprovedUpdates() {
positionContext.startUpdatingPositionDelegate(.improvedPosition)
}

func stopUpdates() {
positionContext.stopUpdatingPositionDelegate()
}

func positionContext(_ positionContext: PositionContext, didUpdatePosition position: PositionObject) {
guard position.hasCoordinates() else { return }
let coordinates = position.getCoordinates()
print("Position: \(coordinates.latitude), \(coordinates.longitude)")
}
}

Read latest snapshots

You can fetch on-demand snapshots for raw or improved position:

if let raw = positionContext.getPosition(.position) {
print(raw.getSatelliteTime())
}

if let improved = positionContext.getPosition(.improvedPosition) {
print(improved.getRoadSpeedLimit())
}

PositionContext operations

Method / PropertyDescription
init(context:)Creates a context bound to a DataSourceContext
delegateAssign a PositionContextDelegate to receive updates
startUpdatingPositionDelegate(_:)Starts updates for .position or .improvedPosition
stopUpdatingPositionDelegate()Stops position updates
getPosition()Returns latest position from default stream
getPosition(_:)Returns latest position for a specific PositionType
getSourceType()Returns source stream type as PositionDataType
getPositionDataType()Returns position data type (.live, .playback, .unavailable)
setSpeedMultiplier(_:)Sets playback/simulation speed multiplier
clean()Performs context cleanup

Raw position data

Raw position data corresponds to PositionType.position. It reflects source-level sensor/location data without map-matching enrichment.

Map matched position data

Map-matched position data corresponds to PositionType.improvedPosition. It enriches raw position with road and terrain context (road modifiers, road speed limits, road info, terrain altitude/slope).

Compare position types

Map-matched positions provide additional data compared to raw positions:

AttributeRawMap MatchedAvailable whenDescription / API
satelliteTimealwaysSensor timestamp in ms since 1970 (getSatelliteTime)
provideralwaysPosition source (getProvider)
latitude & longitudehasCoordinatesGeographic coordinates (getLatitude, getLongitude)
coordinateshasCoordinatesFull CoordinatesObject (getCoordinates)
altitudehasAltitudeAltitude in meters (getAltitude)
speedhasSpeedSpeed in m/s (getSpeed)
speedAccuracyhasSpeedAccuracySpeed accuracy in m/s (getSpeedAccuracy)
coursehasCourseHeading in degrees (getCourse)
courseAccuracyhasCourseAccuracyHeading accuracy in degrees (getCourseAccuracy)
horizontalAccuracyhasHorizontalAccuracyHorizontal accuracy in meters (getHorizontalAccuracy)
verticalAccuracyhasVerticalAccuracyVertical accuracy in meters (getVerticalAccuracy)
fixQualityalwaysTrustworthiness (getFixQuality)
roadModifiershasRoadLocalizationPacked road flags (getRoadModifier)
speedLimitalwaysRoad speed limit in m/s (getRoadSpeedLimit)
roadInfohasRoadLocalizationRoad metadata list (getRoadInfo)
roadAddresshasRoadLocalizationAddress fields from matched road (getRoadAddressFieldNameWithType)
terrainAltitudehasTerrainDataTerrain altitude from map data (getTerrainAltitude)
terrainSlopehasTerrainDataTerrain slope in degrees (getTerrainSlope)
formattedSpeedalwaysLocalized speed/value unit (getFormattedSpeed, getFormattedSpeedUnit)
info

getRoadSpeedLimit can return 0 even for map-matched positions when speed-limit data is unavailable for the current road segment.

PositionObject structure

PositionObject contains both sensor and map-aware metadata.

Core fields and checks

MethodDescription
isValid()Checks if position is valid
getSatelliteTime()Satellite timestamp in milliseconds
getProvider()Position source (unknown, gps, network, sensorFusion, mapMatching, simulation)
getLatitude() / getLongitude()Raw latitude/longitude values
getCoordinates()Position coordinates as CoordinatesObject
getAltitude()Altitude in meters
getSpeed()Current speed in m/s
getSpeedAccuracy()Current speed accuracy in m/s
getCourse()Heading in degrees (0 north, 90 east)
getCourseAccuracy()Heading accuracy in degrees
getHorizontalAccuracy() / getVerticalAccuracy()Accuracy metrics in meters
getFixQuality()Fix confidence (invalid, inertial, low, high)
getType()Data object type (DataType)
getFormattedSpeed() / getFormattedSpeedUnit()Localized speed text and unit

Availability checks are exposed via:

CheckDescription
hasCoordinates()Latitude/longitude available and valid
hasAltitude()Altitude is available
hasSpeed()Speed is available
hasSpeedAccuracy()Speed accuracy is available
hasCourse()Course is available
hasCourseAccuracy()Course accuracy is available
hasHorizontalAccuracy()Horizontal accuracy is available
hasVerticalAccuracy()Vertical accuracy is available

Raw vs improved position data

Use PositionType in PositionContext to choose the stream:

  • Raw position: source-level positioning data
  • Improved position: map-matched data enriched with road and terrain context

Improved-only style fields are exposed through PositionObject when available:

MethodDescription
hasRoadLocalization()Indicates map matching localized the position on a road
getRoadModifier()Packed RoadModifier flags (Tunnel, Bridge, Ramp, etc.)
getRoadSpeedLimit()Current road speed limit in m/s (0 if unavailable)
getRoadInfo()Road metadata list in ascending priority
getRoadCodeImage(_:)Renders road code image (UIImage)
getRoadCodeImage(_:scale:ppi:)Renders road code image with explicit scale/PPI
getRoadAddressFieldNameWithType(_:)Road-address fields from matched position
hasTerrainData()Indicates terrain metadata is available
getTerrainAltitude()Terrain altitude from map data
getTerrainSlope()Current slope in degrees (positive ascent, negative descent)

Decode road modifier flags from improved positions:

if let improved = positionContext.getPosition(.improvedPosition), improved.hasRoadLocalization() {
let flags = improved.getRoadModifier()
// 0x1 is the Tunnel flag in RoadModifier
let isTunnel = (flags & 0x1) != 0
print("isTunnel = \(isTunnel)")
}

Provider and source context

Use PositionProvider and PositionDataType to reason about data origin:

  • Provider indicates where the position came from (GPS, MapMatching, Simulation, etc.)
  • Source type indicates whether data is live or playback (PositionDataTypeLive, PositionDataTypePlayback)

This distinction helps when building simulation flows, diagnostics, and navigation UI behavior.

EnumValues
PositionProviderunknown, gps, network, sensorFusion, mapMatching, simulation
PositionFixQualityinvalid, inertial, low, high
PositionDataTypelive, playback, unavailable

Read context values from PositionContext:

let sourceType = positionContext.getSourceType()
let dataType = positionContext.getPositionDataType()

if dataType == .playback {
positionContext.setSpeedMultiplier(2.0)
}