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.
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 MainApp.swift.
-
In the Editor, set the
ArcGISEnvironment.apiKey
property on theArcGIS
with your copied access token.Environment MainApp.swiftUse dark colors for code blocks init() { ArcGISEnvironment.apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>") }
Update the map
-
In Xcode, in the Project Navigator, click ContentView.swift.
-
In the editor, change the map and viewpoint into two separate
@
variables so that the viewpoint can be changed as the geocode results change.State ContentView.swiftUse dark colors for code blocks 55 56 63Change line Change line Change line Change line Change line Change line struct ContentView: View { @State private var map = Map(basemapStyle: .arcGISImagery) @State private var viewpoint: Viewpoint? = Viewpoint( latitude: 34.02700, longitude: -118.80500, scale: 72_000 )
-
Create a private class named
Model
of typeObservable
and add aObject @
variable of theState Object Model
to theContent
. See the programming patterns page for more information on how to manage states.View ContentView.swiftUse dark colors for code blocks 16 17 18 19 23 24 25 27 28Add line. Add line. Add line. Add line. import SwiftUI import ArcGIS private class Model: ObservableObject { } struct ContentView: View { @StateObject private var model = Model() }
-
Create a
GraphicsOverlay
namedgraphics
in theOverlay Model
class. A graphics overlay is a container for graphics.A graphics overlay is a container for graphics. It is used with a map view to display graphics on a map. You can add more than one graphics overlay to a map view. Graphics overlays are displayed on top of all the other layers.
ContentView.swiftUse dark colors for code blocks 20 21 23 24Add line. private class Model: ObservableObject { let graphicsOverlay: GraphicsOverlay }
-
Lastly, add the viewpoint and graphics overlay to the map view.
ContentView.swiftUse dark colors for code blocks 88 89 91 92Change line var body: some View { MapView(map: map, viewpoint: viewpoint, graphicsOverlays: [model.graphicsOverlay]) }
Add graphics
Graphics are added as a visual means to display the search result on the map.
-
Create a private property named
text
in theGraphic Model
class. This graphic will be used to display the result's text label.A
TextSymbol
is used to display text at a location on the map view.ContentView.swiftUse dark colors for code blocks 20 21 22 23 35 36Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { let graphicsOverlay: GraphicsOverlay let textGraphic: Graphic = { let textSymbol = TextSymbol( text: "", color: .black, size: 14, horizontalAlignment: .center, verticalAlignment: .bottom ) textSymbol.backgroundColor = .white return Graphic(symbol: textSymbol) }() }
-
Create a private property named
marker
in theGraphic Model
class. This graphic will be used to display the result's location.A
SimpleMarkerSymbol
is used to display a location on the map view.ContentView.swiftUse dark colors for code blocks 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 44 45Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. private class Model: ObservableObject { let graphicsOverlay: GraphicsOverlay let textGraphic: Graphic = { let textSymbol = TextSymbol( text: "", color: .black, size: 14, horizontalAlignment: .center, verticalAlignment: .bottom ) textSymbol.backgroundColor = .white return Graphic(symbol: textSymbol) }() let markerGraphic: Graphic = { let markerSymbol = SimpleMarkerSymbol( style: .square, color: .red, size: 14 ) return Graphic(symbol: markerSymbol) }() }
-
Create an
init
function for theModel
class. Create aGraphics
with theOverlay text
andGraphic marker
and assign it to the model's graphics overlay. This function will be called whenGraphic Model
is initialized.Because
text
andGraphic marker
haven't yet specified aGraphic Geometry
, they will not be visible.ContentView.swiftUse dark colors for code blocks 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 48 49Add line. Add line. Add line. private class Model: ObservableObject { let graphicsOverlay: GraphicsOverlay let textGraphic: Graphic = { let textSymbol = TextSymbol( text: "", color: .black, size: 14, horizontalAlignment: .center, verticalAlignment: .bottom ) textSymbol.backgroundColor = .white return Graphic(symbol: textSymbol) }() let markerGraphic: Graphic = { let markerSymbol = SimpleMarkerSymbol( style: .square, color: .red, size: 14 ) return Graphic(symbol: markerSymbol) }() init() { graphicsOverlay = GraphicsOverlay(graphics: [textGraphic, markerGraphic]) } }
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
LocatorTask
property in theModel
, namedlocator
, 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.
ContentView.swiftUse dark colors for code blocks 20 21 22 23 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53Add line. Add line. Add line. private class Model: ObservableObject { let graphicsOverlay: GraphicsOverlay let locator = LocatorTask( url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")! ) let textGraphic: Graphic = { let textSymbol = TextSymbol( text: "", color: .black, size: 14, horizontalAlignment: .center, verticalAlignment: .bottom ) textSymbol.backgroundColor = .white return Graphic(symbol: textSymbol) }() let markerGraphic: Graphic = { let markerSymbol = SimpleMarkerSymbol( style: .square, color: .red, size: 14 ) return Graphic(symbol: markerSymbol) }() init() { graphicsOverlay = GraphicsOverlay(graphics: [textGraphic, markerGraphic]) } }
-
In the
Content
, create a privateView String
variable namedsearch
with theText @
property wrapper. This will hold the user input and be used to perform the geocode operation.State ContentView.swiftUse dark colors for code blocks 55 56 57 58 59 60 61 62 63 64 65 67 68 69 70 71 72 73 74Add line. struct ContentView: View { @StateObject private var model = Model() @State private var map = Map(basemapStyle: .arcGISImagery) @State private var viewpoint: Viewpoint? = Viewpoint( latitude: 34.02700, longitude: -118.80500, scale: 72_000 ) @State private var searchText: String = "" var body: some View { MapView(map: map, viewpoint: viewpoint, graphicsOverlays: [model.graphicsOverlay]) } }
-
Create a private, asynchronous function named
geocode(with
. This function will be called when the user inputs an address.:) ContentView.swiftUse dark colors for code blocks 55 56 57 58 59 60 61 62 63 64 65 66 67 71 72 73 74 75 76 77 78Add line. Add line. Add line. struct ContentView: View { @StateObject private var model = Model() @State private var map = Map(basemapStyle: .arcGISImagery) @State private var viewpoint: Viewpoint? = Viewpoint( latitude: 34.02700, longitude: -118.80500, scale: 72_000 ) @State private var searchText: String = "" private func geocode(with searchText: String) async throws { } var body: some View { MapView(map: map, viewpoint: viewpoint, graphicsOverlays: [model.graphicsOverlay]) } }
-
Within the new function, create
GeocodeParameters
, and its attributes as follows:- Specify which attributes to return with
add
.Result Attribute Name *
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
GeocodeParameters
to control certain aspects of the geocoding operation, and specify the kinds of results to return from the locator task.ContentView.swiftUse dark colors for code blocks 68 69 74 75Add line. Add line. Add line. Add line. private func geocode(with searchText: String) async throws { let parameters = GeocodeParameters() parameters.addResultAttributeName("*") parameters.maxResults = 1 parameters.outputSpatialReference = map.spatialReference }
- Specify which attributes to return with
-
Perform the geocode operation by calling
geocode(for
and supplying the search text and the geocode parameters. The result obtained from the geocode operation will be displayed as a graphic in the map view's graphics overlay.Search Text :using :) ContentView.swiftUse dark colors for code blocks 68 69 70 71 72 73 74 85 86Add 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) async throws { let parameters = GeocodeParameters() parameters.addResultAttributeName("*") parameters.maxResults = 1 parameters.outputSpatialReference = map.spatialReference let geocodeResults = try await model.locator.geocode(forSearchText: searchText, using: parameters) if let firstResult = geocodeResults.first, let extent = firstResult.extent, let location = firstResult.displayLocation, let symbol = model.textGraphic.symbol as? TextSymbol { viewpoint = Viewpoint(boundingGeometry: extent) model.markerGraphic.geometry = location model.textGraphic.geometry = location symbol.text = firstResult.label } }
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.
-
In the
body
, add anoverlay
to theMap
. Set theView alignment
to the top, add padding all around, and set the background.ContentView.swiftUse dark colors for code blocks 88 89 90 91 97 98Add line. Add line. Add line. Add line. Add line. var body: some View { MapView(map: map, viewpoint: viewpoint, graphicsOverlays: [model.graphicsOverlay]) .overlay(alignment: .top) { .padding(EdgeInsets(top: 60, leading: 10, bottom: 10, trailing: 10)) .background(.thinMaterial, ignoresSafeAreaEdges: .horizontal) } }
-
Within the overlay, add the following:
Text
: Pass in "Enter address" as theField title
and theKey search
variable as a binding for theText text
parameterSpacer()
: Add space in between the text field and button.Button
: Label it "Search" and using aTask
method, call thegeocode(with
function and pass in:) search
Text
ContentView.swiftUse dark colors for code blocks 88 89 90 91 92 93 103 104 105 106 107 108Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. var body: some View { MapView(map: map, viewpoint: viewpoint, graphicsOverlays: [model.graphicsOverlay]) .overlay(alignment: .top) { HStack { TextField("Enter address", text: $searchText) Spacer() Button("Search") { Task { try await geocode(with: searchText) } } } .padding(EdgeInsets(top: 60, leading: 10, bottom: 10, trailing: 10)) .background(.thinMaterial, ignoresSafeAreaEdges: .horizontal) } }
-
Press Command + R to run the app.
If you are using the Xcode simulator your system must meet these minimum requirements: macOS Monterey 12.5, Xcode 15, iOS 17. If you are using a physical device, then refer to the system requirements.
You should see a search box at the top of the map. Search for an address by entering an address and tap the Search button. The result of the search should display on the map as a red square with the address displayed on top.