Search for an address

search for an address

Prerequisites

The following are required for this tutorial:

  1. An ArcGIS account to access your API keys. If you don't have an account, sign up for free.
  2. Your system meets the system requirements.
  3. The ArcGIS Runtime API for iOS is installed.

Steps

Open a Xcode project

  1. To start the tutorial, complete the Display a map tutorial or download and unzip the solution.

  2. Open the .xcodeproj file in Xcode.

  3. 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.

    1. 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.

    2. In Xcode, in the Project Navigator, click AppDelegate.swift.

    3. In the editor, set the apiKey property on the AGSArcGISRuntimeEnvironment with your API key.


      AppDelegate.swift
      Change line
                                         
      // Copyright 2020 Esri
      //
      // Licensed under the Apache License, Version 2.0 (the "License");
      // you may not use this file except in compliance with the License.
      // You may obtain a copy of the License at
      //
      //   https://www.apache.org/licenses/LICENSE-2.0
      //
      // Unless required by applicable law or agreed to in writing, software
      // distributed under the License is distributed on an "AS IS" BASIS,
      // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
      // See the License for the specific language governing permissions and
      // limitations under the License.
      
      
      import UIKit
      
      import ArcGIS
      
      
      @UIApplicationMain
      class AppDelegate: UIResponder, UIApplicationDelegate {
          var window: UIWindow?
      
          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.

  1. In Xcode, in the Project Navigator, click ViewController.swift.

  2. In the editor, extend ViewController to conform to the UISearchBarDelegate protocol.

    The UISearchBarDelegate will allow ViewController to receive user interaction messages from a UISearchBar.

    ViewController.swift
    Add line.Add line.Add line.
    146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 146 145 144 143 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 141 140 139 138 137 136 135 134 133 132 132 132 132 131 130 129 128 127 126 125 124 123 122 121 120 119 118 117 116 115 114 113 112 111 110 109 108 107 106 106 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 86 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 50 50 51 52 52 52 52 52 52 52 52 52 52 52 52 52 52 53
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  3. Define a private method named setupSearchBar(). In setupSearchBar() create an UISearchBar with these initial values and assign it to navigationItem.titleView.

    ViewController.swift
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 45 44 43 42 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 41 42 43 44 45 46 47 48 49 50 50 50 50 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 24 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 4 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -28 -29 -30 -31 -32 -32 -32 -32 -32 -33 -34 -35 -36 -37 -38 -39 -40 -41 -42 -43 -44 -45 -45
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  4. In Xcode, in the Project Navigator, click Main.storyboard.

  5. In the editor, select ViewController. In the menu bar, click Editor > Embed In > Navigation Controller.

    Embedding ViewController within a Navigation Controller will place a navigation bar at the top of ViewController. Inside the navigation bar you will find the search bar.

  6. In Xcode, in the Project Navigator, click ViewController.swift.

  7. In the editor, in the viewDidLoad() method, call setupSearchBar().

    ViewController.swift
    Add line.
    20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 21 22 23 24 25 26 26 26 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -19 -19 -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 -45 -46 -47 -48 -49 -50 -51 -52 -53 -54 -55 -55 -55 -55 -55 -56 -57 -58 -59 -60 -61 -62 -63 -64 -65 -66 -67 -68 -68
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    

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.

  1. Create a private AGSGraphic property named textGraphic. This graphic will be used to display the result's text label.

    An AGSTextSymbol is used to display text at a location on the map view.

    ViewController.swift
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 64 63 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 62 61 60 59 58 57 56 57 58 59 60 61 62 63 64 65 66 66 65 64 63 62 61 60 59 58 57 57 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 37 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 1 1 1 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -12
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  2. Create a private AGSGraphic property named markerGraphic. This graphic will be used to display the result's location.

    An AGSSimpleMarkerSymbol is used to display a location on the map view.

    ViewController.swift
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 74 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 73 72 71 70 69 68 67 67 67 67 67 67 67 67 67 67 67 67 68 69 70 71 72 73 74 75 75 75 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 55 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 19 19 19 19 18 17 16 15 14 13 12 11 10 9 8 7 6 6
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  3. Define a private method named setupGraphics(). In setupGraphics() create an AGSGraphicsOverlay. Append textGraphic and markerGraphic to the graphics overlay then add the graphics overlay to the map view.

    ViewController.swift
    Add line.Add line.Add line.Add line.Add line.
    58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 58 57 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 56 57 58 59 60 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 41 41 40 39 38 37 36 35 34 33 32 31 30 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 5 5 5 5 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -8
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    

    Because textGraphic and markerGraphic haven't yet specified a geometry, they will not be visible.

  4. In the viewDidLoad() method, call setupGraphics().

    ViewController.swift
    Add line.
    20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 20 21 22 23 24 25 26 27 28 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 29 28 27 26 25 24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 9 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 -12 -13 -14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 -25 -26 -27 -27 -27 -27 -27 -28 -29 -30 -31 -32 -33 -34 -35 -36 -37 -38 -39 -40 -40
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    

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.

  1. Define an enum named ResultStatus with two cases. The first case, 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.swift
    Add line.Add line.Add line.Add line.
    86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 87 88 89 90 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 75 75 74 73 72 71 70 69 68 67 66 65 64 63 62 61 60 59 58 57 56 55 54 53 52 51 50 49 48 47 46 45 44 43 42 41 40 39 39 39 39 39 38 37 36 35 34 33 32 31 30 29 28 27 26 26
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  2. Create a ResultStatus property named status. Setting this property will update textGraphic and markerGraphic with values from the result.

    ViewController.swift
    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.
    86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 105 105 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 69 69 69 69 68 67 66 65 64 63 62 61 60 59 58 57 56 56
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    

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.

  1. Create a private AGSLocatorTask property named 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.swift
    Add line.Add line.Add line.
    108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 109 110 111 111 110 109 108 107 106 105 104 103 102 101 100 99 98 97 96 95 94 93 92 91 90 89 88 87 86 85 84 83 82 81 80 79 79 79 79 79 78 77 76 75 74 73 72 71 70 69 68 67 66 66
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  2. Create a private optional AGSCancelable property named currentGeocodeOperation 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.

    ViewController.swift
    Add line.
    108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 109 110 111 112 113 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 114 113 113 113 113 113 112 111 110 109 108 107 106 105 104 103 102 101 100 100
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  3. Define a private method named geocode(with searchText: String) and cancel the current geocode operation, if one exists.

    ViewController.swift
    Add line.Add line.Add line.Add line.
    108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 108 109 110 111 112 113 114 115 116 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 117 118 118 118 118 118 118 117 116 115 114 113 112 111 110 109 108 107 106 105 105
    // Copyright 2020 Esri.
    //
    // Licensed under the Apache License, Version 2.0 (the "License");
    // you may not use this file except in compliance with the License.
    // You may obtain a copy of the License at
    //
    //   https://www.apache.org/licenses/LICENSE-2.0
    //
    // Unless required by applicable law or agreed to in writing, software
    // distributed under the License is distributed on an "AS IS" BASIS,
    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    // See the License for the specific language governing permissions and
    // limitations under the License.
    
    import UIKit
    import ArcGIS
    
    class ViewController: UIViewController {
        @IBOutlet weak var mapView: AGSMapView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            setupMap()
    
            setupSearchBar()
    
            setupGraphics()
    
        }
    
        // MARK: - Map
    
        private func setupMap() {
            mapView.map = AGSMap(basemapStyle: .arcGISTopographic)
            mapView.setViewpoint(
                AGSViewpoint(
                    latitude: 34.02700,
                    longitude: -118.80543,
                    scale: 144447.638572
                )
            )
        }
    
        // MARK: - Search Bar
    
        private func setupSearchBar() {
            navigationItem.titleView = {
                let searchBar = UISearchBar()
                searchBar.delegate = self
                searchBar.showsCancelButton = true
                searchBar.placeholder = "Search for an address"
                return searchBar
            }()
        }
    
    
        // MARK: - Graphics
    
        private func setupGraphics() {
            let graphicsOverlay = AGSGraphicsOverlay()
            graphicsOverlay.graphics.addObjects(from: [textGraphic, markerGraphic])
            mapView.graphicsOverlays.add(graphicsOverlay)
        }
    
        private let textGraphic: AGSGraphic = {
            let textSymbol = AGSTextSymbol(
                text: "",
                color: .black,
                size: 14,
                horizontalAlignment: .center,
                verticalAlignment: .bottom
            )
            return AGSGraphic(geometry: nil, symbol: textSymbol)
        }()
    
        private let markerGraphic: AGSGraphic = {
            let markerSymbol = AGSSimpleMarkerSymbol(
                style: .square,
                color: .red,
                size: 12
            )
            return AGSGraphic(geometry: nil, symbol: markerSymbol)
        }()
    
        // MARK: - Result
    
        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
                }
            }
        }
    
        // MARK: - Geocoding
    
        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()
    
            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).")
                }
            }
    
        }
    
    }
    
    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()
        }
    
    }
    
  4. Create new AGSGeocodeParameters, and assign it to the geocodeParameters property. Specify the geocode's attributes as follows:

    • Specify which attributes to return with resultAttributeNames. * is used to return all attributes.

    • Set the maximum number of results to be returned with maxResults. In this tutorial, only return the best match by passing in 1. Results are ordered by score, so just returning the first result will return the highest scoring result.

    • Set the spatial reference with outputSpatialReference. 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 providing mapView.spatialReference as a parameter.

      When geocoding an address, you can optionally provide AGSGeocodeParameters to control certain aspects of the geocoding operation, and specify the kinds of results to return from the locator task.

    ViewController.swift
    Add line.Add line.Add line.Add line.Add line.Add line.Add line.
    114 114 114 114 114