All tutorials
Using the iOS Map Component
Introduction
The easiest way to add what3words to your technology is to use one of our components. We have several components available for JavaScript, iOS, and Android which require minimal development to integrate.
The what3words iOS Map Component provides a straightforward way to add what3words grid on top of your MKMapView
or a full-featured map View Controller, displaying the what3words address and marker on the map for a selected 3 word address.
This tutorial steps through how our iOS Map Component can be added to a new project that requires creating a map from scratch or to an existing map:
- If you are creating a new map from scratch using our Map component then we recommend using our Map Component: W3WMapViewController;
- If you want to add what3words to an existing map then we recommend using our Map Helper: W3WMapHelper;
- If you are looking for a quick and dirty way to get the what3words functionality into your app we recommend using our Map View: W3WMapView.
Follow the steps below to select your chosen way to integrate our what3words map component into your project.<
GitHub repo: https://github.com/what3words/w3w-swift-components.
Quickstart
The iOS Map Component requires just a few lines of code to be added to an iOS application to create a map with what3words functionality.
- Replace YOUR-API-KEY with your what3words API key.
- It is compatible with applications that are built using iOS 9.0 or higher.
- If you are upgrading from any version 1.x.x, see this upgrade guide.
Here are listed some sample apps that can be used:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") let textField = W3WAutoSuggestTextField(api) self.attach(textField: textField) textField.onSuggestionSelected = { suggestion in self.removeAllMarkers() self.addMarker(at: suggestion, camera: .zoom) } self.onSquareSelected = { square in self.removeAllMarkers() self.addMarker(at: square, camera: .center) testField.set(display: square) } let button = W3WMapTypeButton() attach(view: button, position: .bottomRight) // if there is an error then add it as an alert onError = { error in self.showError(error: error) } } /// set here the showError() function func showError(error: Error) { DispatchQueue.main.async { let alert = UIAlertController(title: "Error", message: String(describing: error), preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Dismiss", style: .cancel, handler: nil)) self.present(alert, animated: true) } } }
Step by Step
The iOS Map Component depends on the what3words swift wrapper, make sure you will add it as a Package Dependency. Follow these easy steps to add this swift package to your project:
- From Xcode’s File menu choose
Swift Packages
thenAdd Package Dependancy
. - The Choose Package Repository window appears. Add https://github.com/what3words/w3w-swift-components.git in the search box, and click on
Next
. - If you are satisfied with the selected version branch choices, click Next again.
- You should then be shown as a “Package Product”
W3WSwiftComponents
. ChooseAdd Package
.
Xcode should now automatically install w3w-swift-components
, and w3w-swift-wrapper
.
Go to your ViewController.swift
file and add the following libraries:
import W3WSwiftApi import W3WSwiftComponents
If you are starting a new project and you are creating a new app from scratch, we recommend using our W3WMapViewController which is a high-level component that has easy-to-use what3words functionality.
Add the following class W3WMapViewController
to the ViewController
of your project. You will just have a Map view, no what3words functionality has been added yet at this point.
import UIKit import W3WSwiftApi import W3WSwiftComponents class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() // Do any additional setup after loading the view. } }
You will need to add your what3words API key here to display the Map Component:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") } }
To refer to the map add the following line of code to your viewDidLoad()
function below the api
variable:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") // set the map view --> self = map self.set(api) } }
After adding this snippet run your application and you will display the Apple Maps with the what3words grid on top of it.
Customise the Map Component
The Map Component can be customised using some what3words properties. Here is shown an example where you can add a simple market to your Map with a specified what3words address. It will place an annotation on the map, if the map is zoomed in, it will appear as a square, and if zoomed out it shows as a what3words annotation icon.
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) // add Marker with a specified what3words address self.addMarker(at: "filled.count.soap") } }
You can set a language to get all the 3wa in the desired language (default english) by adding this line of code within the viewDidLoad
function:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) // set language to get all the what3words self.set(language: "en") self.addMarker(at: "filled.count.soap") } }
You can make the map marker change color or their position on the map or add a list of specified what3words addresses.
Note: the default colour of the marker is the brand’s red.
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // an example on how to add a blue marker on a valid 3 word address and move the map view to the center with multiple markers on the map self.addMarker(at:["filled.count.soap", "index.home.raft"], camera: .center, color: .blue) } }
You could also pass in a what3words suggestion to the addMarker
property:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // an example on how to add a what3words suggestions to the marker api.autosuggest(text: "filled.count.s") { suggestions, error in self.addMarker(at: suggestions) } } }
You could also restrict your what3words address suggestions to a desired country using W3WOptions()
as shown here:
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // an example on how to add a what3words suggestions to the marker clipped to a desired country let options = W3WOptions().clipToCountry("GB") api.autosuggest(text: "filled.count.s", options: options) { suggestions, error in self.addMarker(at: suggestions) } } }
Access the map view
To access the Map View you can use an accessor variable called w3wMapView
which is an MKMapView
.
Listening for events
Now when you click on the map marker you can display the what3words address if you trigger the onSquareSelected
event.
Note: Only one square can be selected at the same time, just like our core apps.
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // an example when a point is touched on the map and highlights its 3x3m what3words square, self.onSquareSelected = { square in // this clears previous what3words annotations and selected squares self.removeAllMarkers() self.addMarker(at: square, camera: .center) } } }
Use AutoSuggest Component in the Search field
If you want to add the AutoSuggest Component to the search box on top of the Map Component, you need to update your viewDidLoad()
function to both have the what3words components, the W3WAutoSuggestTextField
(for the AutoSuggest Component) and W3WMapViewController
(for the Map Component).
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // Add an AutoSuggest Component text field, and attach it to the view let textField = W3WAutoSuggestTextField(api) self.attach(textField: textField) // when an AutoSuggest suggestion is selected from the text field, show it on the map and clear previous selections textField.onSuggestionSelected = { suggestion in self.removeAllMarkers() self.addMarker(at: suggestion, camera: .zoom) } self.onSquareSelected = { square in self.removeAllMarkers() self.addMarker(at: square, camera: .center) // this add the what3words address to the text field textField.set(display: square) } } }
If you want to add the voice functionality to the AutoSuggest Text Field Component you need to make sure to add the following line of code right after you declare the textField
variable
let textField = W3WAutoSuggestTextField(api) // Add an AutoSuggest text field component with the voice option, and attach it to the view (voice functionality requires API key permissions, contact what3words to enable this - https://accounts.what3words.com/overview) textField.set(voice: true) attach(textField: textField)
Customise map type
If you are familiar with MKMapView
you can set up different map types MKMapType
, for example:
.standard
if you want to display street map
mapView.mapType = .standard
.satellite
if you want to displays satellite imagery
mapView.mapType = .satellite
Here is what your application should look like:
If you already have an application with a map we recommend using our Map Helper, W3WMapHelper
in your app. It provides convenience functions to add to your MKMapViewDelegate
functions for what3words grid and pin annotations to be displayed on your map.
An iOS UIKit example project can be out here. This example shows where you would place the calls, and how to instantiate the W3WMapHelper
.
Note: the W3WMapHelper
is conforms to the W3WMapViewProtol
. A function reference is described below in the Map Component Functions.
let api = What3WordsV3(apiKey: "YourApiKey") let mapHelper = W3WMapHelper(api, map: yourMKMapView)
If you are keen on using our Map View, W3WMapView
, as a quick and dirty way to quickly get what3words functionality into your app, simply replace your MKMapView
with W3WMapView
, and your app should behave the same as before except it will draw what3words grid lines and have some new functions available, like addMarker(at: "filled.count.soap")
.
The W3WMapView
is derived from MKMapView
but Apple does not recommend deriving new objects from MKMapView
presumably, because its interface could change in the future.
A better approach to inserting our map component into your existing map would be to use our W3WMapHelper
which is designed to fit nicely into your MKMapViewDelegate
conforming class, presumably a UIViewController
.
An iOS UIKit example project can be out here.
Note: the W3WMapHelper
is conforms to the W3WMapViewProtol
. A function reference is described below in the Map Component Functions.
let api = What3WordsV3(apiKey: "YourApiKey") let mapview = W3WMapView(api)
If you run our Enterprise Suite API Server yourself, you may specify the URL to your own server by adding this line of code to the Map Component:
val api = What3WordsV3(apiKey: "YOUR_API_KEY_HERE", apiUrl: "https://api.yourserver.com")
Method Name | Description | Example |
---|---|---|
addMarker(at: _, camera: W3WCenterAndZoom, color: UIColor?, style: W3WMarkerStyle) | This parameter will place an annotation on the map, if the map is zoomed in, it will appear as a square, and if zoomed out it shows as a what3words annotation icon. addMarker(at:camera:color) takes one required parameter and two optional ones. The first is the location, this can be a what3words address as: - words: String, - suggestion: W3WSuggestion, - squares: W3WSquare, - coordinates: CLLocatioinCorrdinate2D, - or it can be an array of any of those. Note: if you pass in a String, or W3WSuggestion, a call to convertToCoordinates will be made automatically to get the coordinates, and this will count towards your account quota. The second and optional parameter is called camera and it indicates how to move the map view. The choices are: - .zoom - zooms the map into the location right around the square - .center - adjusts the map's center so that the location is in the center, but does not zoom in - .none - this leaves the mapView showing the same area it was showing before the call The third and optional parameter is color which takes a UIColor color for the annotation. The default colour is the what3words brand's red. | map.addMarker(at:square, camera: .zoom) map.addMarker(at:"filled.count.soap", style: .pin) map.addMarker(at:["filled.count.soap", "index.home.raft"], camera: .center) map.addMarker(at:["filled.count.soap", "index.home.raft"], color: .blue, camera: .center) |
getMapAnnotationView(annotation: MKAnnotation) -> MKAnnotationView? | If the annotation is a what3words one, this parameter gets a renderer, otherwise, it returns nil. If you are using W3WMapHelper then this is typically called in your MKMapViewDelegate's call: mapView(_, viewFor: MKAnnotation) | getMapAnnotationView(annotation: annotation) |
mapRenderer(overlay: MKOverlay) -> MKOverlayRenderer?addMarkerAtWords | This parameter gets a renderer for the what3words grid if it is given a W3WMapGridLines or W3WMapSquareLines overlay, otherwise, it returns nil. If you are using W3WMapHelper then this is typically called in your MKMapViewDelegate's call: mapView(_, rendererFor: MKOverlay) | mapRenderer(overlay: overlay) |
removeAllMarkers() | This parameter will hide an annotation that was previously placed on the map. It takes one parameter and like addMarker(), it can be a what3words address as: - words: String, - suggestion: W3WSuggestion, - coordinates: CLLocatioinCorrdinate2D, - or it can be an array of any of those. | map.removeAllMarkers() |
removeMarker(at:) | This method allow you to get all added markers from the map. | map.removeMarker(at: square) map.removeMarker(at: "filled.count.soap") map.removeMarker(at: ["filled.count.soap", "index.home.raft"]) |
set(language: String) | This parameter will set the default language for all the calls that the map makes to the API (or SDK if you use that instead). | map.set(language: "fr") // set default language to French |
set(zoomInPointsPerSquare: CGFloat) | This parameter will set how near the addMarker(at: "filled.count.soap", camera: .zoom) calls will zoom. zoomInPointsPerSquare is the size of squares in points when .zoom is used in an addMarker() call. (points being 1x, 2x, 3x a pixel depending on which device you are using and if it has a "retina" display. | set(zoomInPointsPerSquare: x.x) |
updateMap() | This parameter updates the map view with annotations and lines. If you are using W3WMapHelper then this is typically called in your MKMapViewDelegate's calls: mapViewDidChangeVisibleRegion() mapView(_, regionWillChangeAnimated), and mapView(_, regionDidChangeAnimated). | updateMap() |
Event | Description | Example |
---|---|---|
onMarkerSelected | This parameter is called when the user taps a square that has a marker added to it. | self.onMarkerSelected = { square in self.addMarker(at: square, camera: .center)} |
onSquareSelected | This parameter is called when the user taps a square on a map. | self.onSquareSelected = { square in self.addMarker(at: square, camera: .center)} |
onError | This parameter returns the error enum for any error that occurs. | onError = { error in self.showError(error: error) } |
Listening for events
Using an event listener, it is possible to fire other functionality in an app when something changes in the Map Component. For example, when you click on the map marker you can display the what3words address if you trigger the onSquareSelected
event.
Note: Only one square can be selected at the same time, just like our core apps.
class ViewController: W3WMapViewController { override func viewDidLoad() { super.viewDidLoad() let api = What3WordsV3(apiKey: "Enter your what3words API key") self.set(api) self.set(language: "en") // an example when a point is touched on the map and highlights its 3x3m what3words square, self.onSquareSelected = { square in // this clears previous what3words annotations and selected squares self.removeAllMarkers() self.addMarker(at: square, camera: .center) } } }
If you encounter errors or issues related to convert-to-coordinate, convert-to-3wa and grid-section requests while using the Free plan, please check the network panel for the following error message Error 402 payment required
and its response, indicating the need to upgrade to a higher plan:
{ "error": { "code": "QuotaExceeded", "message": "Quota exceeded or API plan does not have access to this feature. Please change your plan at https://accounts.what3words.com/select-plan, or contact support@what3words.com" } }
For more information, visit our API plans page. If you need further assistance, contact support@what3words.com.
Issue
How to make the textfield suggest actual addresses (not w3w)?
Solution
Currently, it’s not possible with the iOS AutoSuggest Component. There is, however, an example of this in w3w-swift-wrapper called AutosuggestPlusYourData. You can use this as a guide or even take some of the code from it for your use.