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
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 MainApp.swift.
- In the Editor, set the
ArcGISEnvironment.apiKey
property on theArcGISEnvironment
with your API key.
MainApp.swiftUse dark colors for code blocks import SwiftUI import ArcGIS @main struct MainApp: App { init() { ArcGISEnvironment.apiKey = APIKey("<#your-API-key#>") } var body: some SwiftUI.Scene { WindowGroup { ContentView() .ignoresSafeArea() } } }
-
Update the map
-
In Xcode, in the Project Navigator, click ContentView.swift.
-
In the editor, change the map and viewpoint into two separate
@State
variables so that the viewpoint can be changed as the geocode results change.ContentView.swiftUse dark colors for code blocks Change 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 @State
variable of theObject Model
to theContent
. See the programming patterns page for more information on how to manage states.View ContentView.swiftUse dark colors for code blocks Add 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 Add 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 Change 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 Add 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 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) }() 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 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) }() 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
, 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.
ContentView.swiftUse dark colors for code blocks Add 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 @State
property wrapper. This will hold the user input and be used to perform the geocode operation.ContentView.swiftUse dark colors for code blocks 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 = "" 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 Add 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 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 }
- 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 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) 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 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) { .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 Add 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.