Learn how to find an address or place with a search bar and the Geocoding service.
Geocoding is the process of converting address or place text into a location. The geocoding service can search for an address or a place and perform reverse geocoding.
In this tutorial, you use a search bar in the user interface to access the geocoding service and search for addresses and places.
To learn how to use the geocoding service to reverse geocode, visit the Reverse geocode tutorial.
Prerequisites
Before starting this tutorial:
-
You need an ArcGIS Location Platform or ArcGIS Online account.
-
Your system meets the system requirements.
Steps
Get an access token
You need an access token to use the location services used in this tutorial.
-
Go to the Create an API key tutorial to obtain an access token.
-
Ensure that the following privileges are enabled: Location services > Basemaps > Basemap styles service and Location services > Geocoding.
-
Copy the access token as it will be used in the next step.
To learn more about other ways to get an access token, go to Types of authentication.
Open the Xcode project
-
To start the tutorial, complete the Display a map tutorial or download and unzip the solution.
-
Open the
.xcodeproj
file in Xcode. -
In Xcode, in the Project Navigator, click AppDelegate.swift.
-
In the editor, set the
API
property on theKey AGS
with your access token.ArcGIS Runtime Environment AppDelegate.swiftUse dark colors for code blocks func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { AGSArcGISRuntimeEnvironment.apiKey = "YOUR_ACCESS_TOKEN" return true }
Add a search bar to the UI
To search an address using the application, add a UI element to prompt the user for text input. The text input will be used as the geocode search text in a later step.
-
In Xcode, in the Project Navigator, click ViewController.swift.
-
In the editor, extend
View
to conform to theController UI
protocol.Search Bar Delegate The
UI
will allowSearch Bar Delegate View
to receive user interaction messages from aController UI
.Search Bar ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. extension ViewController: UISearchBarDelegate { }
-
Define a private method named
setup
. InSearch Bar() setup
create anSearch Bar() UI
with these initial values and assign it toSearch Bar navigation
.Item.title View ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private func setupSearchBar() { navigationItem.titleView = { let searchBar = UISearchBar() searchBar.delegate = self searchBar.showsCancelButton = true searchBar.placeholder = "Search for an address" return searchBar }() }
-
In Xcode, in the Project Navigator, click Main.storyboard.
-
In the editor, select
View
. In the menu bar, click Editor > Embed In > Navigation Controller.Controller Embedding
View
within a Navigation Controller will place a navigation bar at the top ofController View
. Inside the navigation bar you will find the search bar.Controller -
In Xcode, in the Project Navigator, click ViewController.swift.
-
In the editor, in the
view
method, callDid Load() setup
.Search Bar() ViewController.swiftUse dark colors for code blocks 21 22 23 24 26 27Add line. override func viewDidLoad() { super.viewDidLoad() setupMap() setupSearchBar() }
Add graphics to the map view
A graphics overlay is a container for graphics. Graphics are added as a visual means to display the search result on the map.
-
Create a private
AGS
property namedGraphic text
. This graphic will be used to display the result's text label.Graphic An
AGS
is used to display text at a location on the map view.Text Symbol ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private let textGraphic: AGSGraphic = { let textSymbol = AGSTextSymbol( text: "", color: .black, size: 14, horizontalAlignment: .center, verticalAlignment: .bottom ) return AGSGraphic(geometry: nil, symbol: textSymbol) }()
-
Create a private
AGS
property namedGraphic marker
. This graphic will be used to display the result's location.Graphic An
AGS
is used to display a location on the map view.Simple Marker Symbol ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private let markerGraphic: AGSGraphic = { let markerSymbol = AGSSimpleMarkerSymbol( style: .square, color: .red, size: 12 ) return AGSGraphic(geometry: nil, symbol: markerSymbol) }()
-
Define a private method named
setup
. InGraphics() setup
create anGraphics() AGS
. AppendGraphics Overlay text
andGraphic marker
to the graphics overlay then add the graphics overlay to the map view.Graphic ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. Add line. private func setupGraphics() { let graphicsOverlay = AGSGraphicsOverlay() graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic]) mapView.graphicsOverlays.add(graphicsOverlay) }
Because
text
andGraphic marker
haven't yet specified a geometry, they will not be visible.Graphic -
In the
view
method, callDid Load() setup
.Graphics() ViewController.swiftUse dark colors for code blocks 21 22 23 24 25 26 28 29Add line. override func viewDidLoad() { super.viewDidLoad() setupMap() setupSearchBar() setupGraphics() }
Define app geocode results status
The app will leverage a state-machine design pattern to ensure the contents of the map reflect the state of the search result. This design pattern supports wrangling multiple asynchronous requests to the world geocoding service into a single state variable result, ensuring the reliability of search results.
-
Define an enum named
Result
with two cases. The first case,Status none
, is used when there is no result or an error is returned. The second case,result
, is used when a result is found.ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. Add line. enum ResultStatus { case none case result(String, AGSPoint) }
-
Create a
Result
property namedStatus status
. Setting this property will updatetext
andGraphic marker
with values from the result.Graphic ViewController.swiftUse dark colors for code blocks 87 88 89 90 91Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. enum ResultStatus { case none case result(String, AGSPoint) } var status: ResultStatus = .none { didSet { switch status { case .none: (textGraphic.symbol as! AGSTextSymbol).text = "" textGraphic.geometry = nil markerGraphic.geometry = nil case .result(let title, let location): (textGraphic.symbol as! AGSTextSymbol).text = title textGraphic.geometry = location markerGraphic.geometry = location } } }
Create a locator task with geocode parameters
Geocoding is implemented with a locator, typically created by referencing a service such as the Geocoding service or, for offline geocoding, by referencing locator data contained in a mobile package. Geocoding parameters can be used to fine-tune the results, such as setting the maximum number of results or requesting additional attributes in the results.
-
Create a private
AGS
property namedLocator Task locator
based on the Geocoding service.A locator task is used to convert an address to a point (geocode) or vice-versa (reverse geocode). An address includes any type of information that distinguishes a place. A locator involves finding matching locations for a given address. Reverse-geocoding is the opposite and finds the closest address for a given point.
ViewController.swiftUse dark colors for code blocks Add line. Add line. Add line. private let locator = AGSLocatorTask( url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")! )
-
Create a private optional
AGS
property namedCancelable current
that will maintain a reference to the geocode operation. If the user submits a second query before the current one completes, it can be used to cancel the operation.Geocode Operation ViewController.swiftUse dark colors for code blocks 109 110 111 112 114Add line. private let locator = AGSLocatorTask( url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")! ) private var currentGeocodeOperation: AGSCancelable?
-
Define a private method named
geocode(with search
and cancel the current geocode operation, if one exists.Text : String) ViewController.swiftUse dark colors for code blocks 109 110 111 112 113 114Add line. Add line. Add line. Add line. private let locator = AGSLocatorTask( url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")! ) private var currentGeocodeOperation: AGSCancelable? private func geocode(with searchText: String) { currentGeocodeOperation?.cancel() }
-
Create new
AGS
, and assign it to theGeocode Parameters geocode
property. Specify the geocode's attributes as follows:Parameters - Specify which attributes to return with
result
.Attribute Names *
is used to return all attributes. - Set the maximum number of results to be returned with
max
. In this tutorial, only return the best match by passing inResults 1
. Results are ordered byscore
, so just returning the first result will return the highest scoring result. - Set the spatial reference with
output
. By default the output spatial reference is determined by the geocode service. For optimal performance when displaying the geocode result, ensure the returned coordinates match those of the map view by providingSpatial Reference map
as a parameter.View.spatial Reference
When geocoding an address, you can optionally provide
AGS
to control certain aspects of the geocoding operation, and specify the kinds of results to return from the locator task.Geocode Parameters ViewController.swiftUse dark colors for code blocks 115 116 117 125 126Add line. Add line. Add line. Add line. Add line. Add line. Add line. private func geocode(with searchText: String) { currentGeocodeOperation?.cancel() let parameters: AGSGeocodeParameters = { let parameters = AGSGeocodeParameters() parameters.resultAttributeNames = ["*"] parameters.maxResults = 1 parameters.outputSpatialReference = mapView.spatialReference return parameters }() }
- Specify which attributes to return with
-
Perform the geocode operation by calling
geocode
and supplying the search query and the geocode parameters. Handle the operation's completion and set the result status accordingly. The result obtained from the geocode operation will be displayed as a graphic in the map view's graphics overlay.With Search Text :parameters :completion :() ViewController.swiftUse dark colors for code blocks 115 116 117 118 119 120 121 122 123 124 125 142 143Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private func geocode(with searchText: String) { currentGeocodeOperation?.cancel() let parameters: AGSGeocodeParameters = { let parameters = AGSGeocodeParameters() parameters.resultAttributeNames = ["*"] parameters.maxResults = 1 parameters.outputSpatialReference = mapView.spatialReference return parameters }() currentGeocodeOperation = self.locator.geocode(withSearchText: searchText, parameters: parameters) { [weak self] (results, error) in guard let self = self else { return } if let error = error { self.status = .none print(error.localizedDescription) return } else if let firstResult = results?.first, let extent = firstResult.extent, let location = firstResult.displayLocation { self.status = .result(firstResult.label, location) self.mapView.setViewpointGeometry(extent) } else { self.status = .none print("No results found for \(searchText).") } } }
Hook up the search bar to the geocode operation
-
Find the
View
extension ofController UI
and introduce theSearch Bar Delegate search
search bar delegate method. Use this method to know when the user presses Search and to perform the geocode operation.Bar Search Button Clicked( _:) ViewController.swiftUse dark colors for code blocks 147 148 157 158Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. extension ViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() guard let searchText = searchBar.text, !searchText.isEmpty else { print("Nothing to search!") return } geocode(with: searchText) } }
-
Introduce the
search
search bar delegate method. Use this method to know when the user presses Cancel and to dismiss the keyboard.Bar Cancel Button Clicked( _:) ViewController.swiftUse dark colors for code blocks 147 148 149 150 151 152 153 154 155 156 157 161 162Add line. Add line. Add line. extension ViewController: UISearchBarDelegate { func searchBarSearchButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() guard let searchText = searchBar.text, !searchText.isEmpty else { print("Nothing to search!") return } geocode(with: searchText) } func searchBarCancelButtonClicked(_ searchBar: UISearchBar) { searchBar.resignFirstResponder() } }
-
Press Command + R to run the app.
If you are using the Xcode simulator your system must meet these minimum requirements: macOS Big Sur 11.3, Xcode 13, iOS 13. If you are using a physical device, then refer to the system requirements.
You should see a search box on the top left of the map. Search for an address by entering an address and press Search on the keyboard. The result of the search should display on the map as a red square.
What's next?
Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials: