Labsco
mapbox logo

mapbox-ios-patterns

68

by mapbox · part of mapbox/mapbox-agent-skills

Official integration patterns for Mapbox Maps SDK on iOS. Covers installation, adding markers, user location, custom data, styles, camera control, and…

🔥🔥🔥🔥✓ VerifiedFreeQuick setup
🧩 One of 7 skills in the mapbox/mapbox-agent-skills package — works on its own, and pairs well with its siblings.

Official integration patterns for Mapbox Maps SDK on iOS. Covers installation, adding markers, user location, custom data, styles, camera control, and…

Inspect the full instructions your agent will receiveExpand

This is the exact playbook injected into your agent when the skill activates — shown here so you can audit it before installing. You don't need to read it to use the skill.

by mapbox

Official integration patterns for Mapbox Maps SDK on iOS. Covers installation, adding markers, user location, custom data, styles, camera control, and… npx skills add https://github.com/mapbox/mapbox-agent-skills --skill mapbox-ios-patterns Download ZIPGitHub68

Mapbox iOS Integration Patterns

Official patterns for integrating Mapbox Maps SDK v11 on iOS with Swift, SwiftUI, and UIKit.

Use this skill when:

  • Installing and configuring Mapbox Maps SDK for iOS

  • Adding markers and annotations to maps

  • Showing user location and tracking with camera

  • Adding custom data (GeoJSON) to maps

  • Working with map styles, camera, or user interaction

  • Handling feature interactions and taps

Official Resources:

Map Initialization

SwiftUI Pattern

Basic map:

Copy & paste — that's it
import SwiftUI
import MapboxMaps

struct ContentView: View {
 @State private var viewport: Viewport = .camera(
 center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
 zoom: 12
 )

 var body: some View {
 Map(viewport: $viewport)
 .mapStyle(.standard)
 }
}

With ornaments:

Copy & paste — that's it
Map(viewport: $viewport)
 .mapStyle(.standard)
 .ornamentOptions(OrnamentOptions(
 scaleBar: .init(visibility: .visible),
 compass: .init(visibility: .adaptive),
 logo: .init(position: .bottomLeading)
 ))

UIKit Pattern

Copy & paste — that's it
import UIKit
import MapboxMaps

class MapViewController: UIViewController {
 private var mapView: MapView!

 override func viewDidLoad() {
 super.viewDidLoad()

 let options = MapInitOptions(
 cameraOptions: CameraOptions(
 center: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194),
 zoom: 12
 )
 )

 mapView = MapView(frame: view.bounds, mapInitOptions: options)
 mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
 view.addSubview(mapView)

 mapView.mapboxMap.loadStyle(.standard)
 }
}

Add Markers

The SDK offers three ways to place a point on the map. Pick the simplest one that fits.

Which API should I use?

API Use it when Platforms Notes Marker (Markers API) You need a default pin and don't have a custom image asset SwiftUI only No image assets required. Experimental SPI — needs @_spi(Experimental) import MapboxMaps. Best < 100 markers. PointAnnotation You have a custom image and want layer-level placement SwiftUI + UIKit Backed by a symbol layer, so it scales well to hundreds of markers. Accepts any UIImage that UIKit can render. View annotations (ViewAnnotation / MapViewAnnotation) You want to render a full native view (card, badge, animated content) anchored to a coordinate SwiftUI + UIKit SwiftUI uses MapViewAnnotation; UIKit uses mapView.viewAnnotations with a ViewAnnotation. Each annotation is a real view — costs more than PointAnnotation at scale.

For hundreds or thousands of features, use a style layer (SymbolLayer on a GeoJSONSource) instead of annotations.

Markers API (recommended for simple cases, SwiftUI)

Copy & paste — that's it
import SwiftUI
@_spi(Experimental) import MapboxMaps

struct ContentView: View {
 var body: some View {
 Map {
 Marker(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
 .color(.red)
 .text("San Francisco")
 }
 }
}

Multiple markers from a collection:

Copy & paste — that's it
Map {
 ForEvery(locations, id: \.id) { location in
 Marker(coordinate: location.coordinate)
 .color(.red)
 .text(location.name)
 }
}

Scaling note. Marker and PointAnnotation each create their own view or symbol entry per pin — fine up to about 100 markers. For larger datasets (hundreds or thousands of features — common with open-ended GeoJSON feeds), load the data into a GeoJSONSource and render it with a SymbolLayer instead. That scales to thousands of features and enables clustering.

PointAnnotation (custom image)

SwiftUI:

Copy & paste — that's it
Map(viewport: $viewport) {
 PointAnnotation(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
 .image(.init(image: UIImage(named: "marker")!, name: "marker"))
}

UIKit:

Copy & paste — that's it
// Create annotation manager (once, reuse for updates)
var pointAnnotationManager = mapView.annotations.makePointAnnotationManager()

// Create marker
var annotation = PointAnnotation(coordinate: CLLocationCoordinate2D(latitude: 37.7749, longitude: -122.4194))
annotation.image = .init(image: UIImage(named: "marker")!, name: "marker")
annotation.iconAnchor = .bottom

// Add to map
pointAnnotationManager.annotations = [annotation]

Multiple markers:

Copy & paste — that's it
let annotations = locations.map { coordinate in
 var annotation = PointAnnotation(coordinate: coordinate)
 annotation.image = .init(image: UIImage(named: "marker")!, name: "marker")
 return annotation
}

pointAnnotationManager.annotations = annotations

Show User Location

Step 1: Add location permission to Info.plist:

Copy & paste — that's it
 NSLocationWhenInUseUsageDescription 
 Show your location on the map 

Step 2: Request permissions and show location:

Copy & paste — that's it
import CoreLocation

// Request permissions
let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()

// Show user location puck
mapView.location.options.puckType = .puck2D()
mapView.location.options.puckBearingEnabled = true

Performance Best Practices

Reuse Annotation Managers

Copy & paste — that's it
// ❌ Don't create new managers repeatedly
func updateMarkers() {
 let manager = mapView.annotations.makePointAnnotationManager()
 manager.annotations = markers
}

// ✅ Create once, reuse
let pointAnnotationManager: PointAnnotationManager

init() {
 pointAnnotationManager = mapView.annotations.makePointAnnotationManager()
}

func updateMarkers() {
 pointAnnotationManager.annotations = markers
}

Batch Annotation Updates

Copy & paste — that's it
// ✅ Update all at once
pointAnnotationManager.annotations = newAnnotations

// ❌ Don't update one by one
for annotation in newAnnotations {
 pointAnnotationManager.annotations.append(annotation)
}

Memory Management

Copy & paste — that's it
// Use weak self in closures
mapView.gestures.onMapTap.observe { [weak self] context in
 self?.handleTap(context.coordinate)
}.store(in: &cancelables)

// Clean up on deinit
deinit {
 cancelables.forEach { $0.cancel() }
}

Use Standard Style

Copy & paste — that's it
// ✅ Standard style is optimized and recommended
.mapStyle(.standard)

// Use other styles only when needed for specific use cases
.mapStyle(.standardSatellite) // Satellite imagery

Reference Files

Load these references when the task requires deeper patterns:

  • references/annotations.md — Circle, Polyline, Polygon Annotations

  • references/location-tracking.md — Camera Follow User + Get Current Location

  • references/custom-data.md — GeoJSON: Lines, Polygons, Points, Update/Remove

  • references/camera-styles.md — Camera Control + Map Styles

  • references/interactions.md — Featureset Interactions, Custom Layer Taps, Long Press, Gestures

Additional Resources