MapboxGeocoder
MapboxGeocoder.swift makes it easy to connect your iOS, macOS, tvOS, or watchOS application to the Mapbox Geocoding API. MapboxGeocoder.swift exposes the power of the Carmen geocoder through a simple API similar to Core Location’s CLGeocoder.
Note that use of the Geocoding API via MapboxGeocoder.swift is billed by API requests. For more information, see the Geocoding API pricing documentation.
MapboxGeocoder.swift pairs well with Mapbox Directions for Swift, MapboxStatic.swift, and the Mapbox Maps SDK for iOS or the Mapbox Maps SDK for macOS.
Getting started
Specify the following dependency in your Carthage Cartfile:
github "mapbox/MapboxGeocoder.swift" ~> 0.14
Or in your CocoaPods Podfile:
pod 'MapboxGeocoder.swift', '~> 0.14'
Or in your Swift Package Manager Package.swift:
.package(url: "https://github.com/mapbox/MapboxGeocoder.swift.git", from: "0.14.0")
Then import MapboxGeocoder
or @import MapboxGeocoder;
.
For Objective-C targets, it may be necessary to enable the ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES
build setting.
This repository includes example applications written in both Swift and Objective-C showing use of the framework (as well as a comparison of writing apps in either language). The Mapbox API Documentation explains the underlying HTTP request and response format, as well as relevant limits that also apply when using this library.
System requirements
- One of the following package managers:
- CocoaPods (CocoaPods 1.10 or above if using Xcode 12)
- Carthage 0.19 or above (run this script instead of
carthage
if using Xcode 12) - Swift Package Manager 5.3 or above
- Xcode 11 or above (Xcode 12 or above if using Swift Package Manager)
- One of the following operating systems:
- iOS 10.0 or above
- macOS 10.12.0 or above
- tvOS 10.0 or above
- watchOS 3.0 or above
Usage
You will need a Mapbox access token in order to use the API. If you’re already using the Mapbox Maps SDK for iOS or Mapbox Maps SDK for macOS, MapboxGeocoder.swift automatically recognizes your access token, as long as you’ve placed it in the MGLMapboxAccessToken
key of your application’s Info.plist file.
The examples below are each provided in Swift (denoted with main.swift
) and Objective-C (main.m
). For further details about each class and method, use the Quick Help feature inside Xcode.
Basics
The main geocoder class is Geocoder in Swift or MBGeocoder in Objective-C. Create a geocoder object using your access token:
// main.swift
import MapboxGeocoder
let geocoder = Geocoder(accessToken: "<#your access token#>")
// main.m
@import MapboxGeocoder;
MBGeocoder *geocoder = [[MBGeocoder alloc] initWithAccessToken:@"<#your access token#>"];
Alternatively, you can place your access token in the MGLMapboxAccessToken
key of your application’s Info.plist file, then use the shared geocoder object:
// main.swift
let geocoder = Geocoder.shared
// main.m
MBGeocoder *geocoder = [MBGeocoder sharedGeocoder];
With the geocoder in hand, construct a geocode options object and pass it into the Geocoder.geocode(_:completionHandler:)
method.
Forward geocoding
Forward geocoding takes a human-readable query, such as a place name or address, and produces any number of geographic coordinates that correspond to that query. To perform forward geocoding, use ForwardGeocodeOptions in Swift or MBForwardGeocodeOptions in Objective-C.
// main.swift
#if canImport(Contacts)
import Contacts
#endif
let options = ForwardGeocodeOptions(query: "200 queen street")
// To refine the search, you can set various properties on the options object.
options.allowedISOCountryCodes = ["CA"]
options.focalLocation = CLLocation(latitude: 45.3, longitude: -66.1)
options.allowedScopes = [.address, .pointOfInterest]
let task = geocoder.geocode(options) { (placemarks, attribution, error) in
guard let placemark = placemarks?.first else {
return
}
print(placemark.name)
// 200 Queen St
print(placemark.qualifiedName)
// 200 Queen St, Saint John, New Brunswick E2L 2X1, Canada
let coordinate = placemark.location.coordinate
print("\(coordinate.latitude), \(coordinate.longitude)")
// 45.270093, -66.050985
#if canImport(Contacts)
let formatter = CNPostalAddressFormatter()
print(formatter.string(from: placemark.postalAddress!))
// 200 Queen St
// Saint John New Brunswick E2L 2X1
// Canada
#endif
}
// main.m
#if !TARGET_OS_TV
@import Contacts;
#endif
MBForwardGeocodeOptions *options = [[MBForwardGeocodeOptions alloc] initWithQuery:@"200 queen street"];
// To refine the search, you can set various properties on the options object.
options.allowedISOCountryCodes = @[@"CA"];
options.focalLocation = [[CLLocation alloc] initWithLatitude:45.3 longitude:-66.1];
options.allowedScopes = MBPlacemarkScopeAddress | MBPlacemarkScopePointOfInterest;
NSURLSessionDataTask *task = [geocoder geocodeWithOptions:options
completionHandler:^(NSArray<MBGeocodedPlacemark *> * _Nullable placemarks,
NSString * _Nullable attribution,
NSError * _Nullable error) {
MBPlacemark *placemark = placemarks[0];
NSLog(@"%@", placemark.name);
// 200 Queen St
NSLog(@"%@", placemark.qualifiedName);
// 200 Queen St, Saint John, New Brunswick E2L 2X1, Canada
CLLocationCoordinate2D coordinate = placemark.location.coordinate;
NSLog(@"%f, %f", coordinate.latitude, coordinate.longitude);
// 45.270093, -66.050985
#if !TARGET_OS_TV
CNPostalAddressFormatter *formatter = [[CNPostalAddressFormatter alloc] init];
NSLog(@"%@", [formatter stringFromPostalAddress:placemark.postalAddress]);
// 200 Queen St
// Saint John New Brunswick E2L 2X1
// Canada
#endif
}];
Reverse geocoding
Reverse geocoding takes a geographic coordinate and produces a hierarchy of places, often beginning with an address, that describes the coordinate’s location. To perform reverse geocoding, use ReverseGeocodeOptions in Swift or MBReverseGeocodeOptions in Objective-C.
// main.swift
let options = ReverseGeocodeOptions(coordinate: CLLocationCoordinate2D(latitude: 40.733, longitude: -73.989))
// Or perhaps: ReverseGeocodeOptions(location: locationManager.location)
let task = geocoder.geocode(options) { (placemarks, attribution, error) in
guard let placemark = placemarks?.first else {
return
}
print(placemark.imageName ?? "")
// telephone
print(placemark.genres?.joined(separator: ", ") ?? "")
// computer, electronic
print(placemark.administrativeRegion?.name ?? "")
// New York
print(placemark.administrativeRegion?.code ?? "")
// US-NY
print(placemark.place?.wikidataItemIdentifier ?? "")
// Q60
}
// main.m
MBReverseGeocodeOptions *options = [[MBReverseGeocodeOptions alloc] initWithCoordinate: CLLocationCoordinate2DMake(40.733, -73.989)];
// Or perhaps: [[MBReverseGeocodeOptions alloc] initWithLocation:locationManager.location]
NSURLSessionDataTask *task = [geocoder geocodeWithOptions:options
completionHandler:^(NSArray<MBGeocodedPlacemark *> * _Nullable placemarks,
NSString * _Nullable attribution,
NSError * _Nullable error) {
MBPlacemark *placemark = placemarks[0];
NSLog(@"%@", placemark.imageName);
// telephone
NSLog(@"%@", [placemark.genres componentsJoinedByString:@", "]);
// computer, electronic
NSLog(@"%@", placemark.administrativeRegion.name);
// New York
NSLog(@"%@", placemark.administrativeRegion.code);
// US-NY
NSLog(@"%@", placemark.place.wikidataItemIdentifier);
// Q60
}];
Batch geocoding
With batch geocoding, you can perform up to 50 distinct forward or reverse geocoding requests simultaneously and store the results in a private database. Create a ForwardBatchGeocodingOptions or ReverseBatchGeocodingOptions object in Swift, or an MBForwardBatchGeocodingOptions or MBReverseBatchGeocodingOptions object in Objective-C, and pass it into the Geocoder.batchGeocode(_:completionHandler:)
method.
// main.swift
let options = ForwardBatchGeocodeOptions(queries: ["skyline chili", "gold star chili"])
options.focalLocation = locationManager.location
options.allowedScopes = .pointOfInterest
let task = geocoder.batchGeocode(options) { (placemarksByQuery, attributionsByQuery, error) in
guard let placemarksByQuery = placemarksByQuery else {
return
}
let nearestSkyline = placemarksByQuery[0][0].location
let distanceToSkyline = nearestSkyline.distance(from: locationManager.location)
let nearestGoldStar = placemarksByQuery[1][0].location
let distanceToGoldStar = nearestGoldStar.distance(from: locationManager.location)
let distance = LengthFormatter().string(fromMeters: min(distanceToSkyline, distanceToGoldStar))
print("Found a chili parlor \(distance) away.")
}
// main.m
MBForwardBatchGeocodeOptions *options = [[MBForwardBatchGeocodeOptions alloc] initWithQueries:@[@"skyline chili", @"gold star chili"]];
options.focalLocation = locationManager.location;
options.allowedScopes = MBPlacemarkScopePointOfInterest;
NSURLSessionDataTask *task = [geocoder batchGeocodeWithOptions:options
completionHandler:^(NSArray<NSArray<MBGeocodedPlacemark *> *> * _Nullable placemarksByQuery,
NSArray<NSString *> * _Nullable attributionsByQuery,
NSError * _Nullable error) {
if (!placemarksByQuery) {
return;
}
MBPlacemark *nearestSkyline = placemarksByQuery[0][0].location;
CLLocationDistance distanceToSkyline = [nearestSkyline distanceFromLocation:locationManager.location];
MBPlacemark *nearestGoldStar = placemarksByQuery[1][0].location;
CLLocationDistance distanceToGoldStar = [nearestGoldStar distanceFromLocation:locationManager.location];
NSString *distance = [NSLengthFormatter stringFromMeters:MIN(distanceToSkyline, distanceToGoldStar)];
NSLog(@"Found a chili parlor %@ away.", distance);
}];
Batch geocoding is available to Mapbox enterprise accounts. See the Mapbox Geocoding website for more information.
Tests
To run the included unit tests, you need to use Carthage 0.19 or above to install the dependencies.
carthage bootstrap
open MapboxGeocoder.xcodeproj
- Switch to the “MapboxGeocoder iOS” scheme and go to Product ‣ Test.
Alternatively, open Package.swift in Xcode and go to Product ‣ Test, or run swift test
on the command line.