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
The following are required for this tutorial:
- An ArcGIS account to access your API keys. If you don't have an account, sign up for free.
- Your system meets the system requirements.
Steps
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. -
If you downloaded the solution project, set your API key.
An API Key enables access to services, web maps, and web scenes hosted in ArcGIS Online.
-
Go to your developer dashboard to get your API key. For these tutorials, use your default API key. It is scoped to include all of the services demonstrated in the tutorials.
- In Xcode, in the Project Navigator, click AppDelegate.swift.
- In the editor, set the
APIKey
property on theAGSArcGISRuntime
with your API key.Environment
AppDelegate.swiftUse dark colors for code blocks func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool { // Note: it is not best practice to store API keys in source code. // The API key is referenced here for the convenience of this tutorial. AGSArcGISRuntimeEnvironment.apiKey = "YOUR_API_KEY" 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 UISearch
protocol.B a r Delegate The
UISearch
will allowB a r Delegate View
to receive user interaction messages from aController UISearch
.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() UISearch
with these initial values and assign it toBar 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, callD i d Load() setup
.Search Bar() ViewController.swiftUse dark colors for code blocks Add 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
AGSGraphic
property namedtext
. This graphic will be used to display the result's text label.Graphic An
AGSText
is used to display text at a location on the map view.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
AGSGraphic
property namedmarker
. This graphic will be used to display the result's location.Graphic An
AGSSimple
is used to display a location on the map view.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() AGSGraphics
. AppendOverlay 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, callD i d Load() setup
.Graphics() ViewController.swiftUse dark colors for code blocks Add 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 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. 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
AGSLocator
property namedTask locator
with the Geocoding service URL.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
AGSCancelable
property namedcurrent
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 Add 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 Add 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
AGSGeocode
, and assign it to theParameters 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
AGSGeocode
to control certain aspects of the geocoding operation, and specify the kinds of results to return from the locator task.Parameters ViewController.swiftUse dark colors for code blocks 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 }() }
- 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 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. 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 UISearch
and introduce theB a r Delegate search
search bar delegate method. Use this method to know when the user presses Search and to perform the geocode operation.B a r Search Button Clicked(_ : ) ViewController.swiftUse dark colors for code blocks Add 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.B a r Cancel Button Clicked(_ : ) ViewController.swiftUse dark colors for code blocks 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) } 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: