A RetroSearch Logo

Home - News ( United States | United Kingdom | Italy | Germany ) - Football scores

Search Query:

Showing content from https://developers.arcgis.com/swift/geocode-and-search/tutorials/find-places/ below:

Find places | ArcGIS Maps SDK for Swift

Learn how to search for places of interest, such as hotels, cafes, and gas stations using the geocoding service.

Geocoding is the process of transforming an address or place name to a location on the earth's surface. A geocoding service allows you to quickly find places that meet specific criteria.

In this tutorial, you use a picklist in the user interface to select a category of places, for example, coffee shops or gas stations. You locate all the places that match this category by accessing a geocoding service. The places are displayed on the map so that you can click on them to get further information.

ArcGIS REST API

This tutorial uses the geocoding service. For more information, see Geocoding service.

Prerequisites

Before starting this tutorial:

  1. You need an ArcGIS Location Platform or ArcGIS Online account.

  2. Your system meets the system requirements.

Set up authentication

To access the secure ArcGIS location services used in this tutorial, you must implement API key authentication or user authentication using an ArcGIS Location Platform or an ArcGIS Online account.

You can implement API key authentication or user authentication in this tutorial. Compare the differences below:

API key authentication

Learn more in API key authentication.

User authentication

Learn more in User authentication.

Security and authentication guide

To learn more about the different types of authentication, visit Types of authentication.

Create a new API key access token with privileges to access the secure resources used in this tutorial.

  1. Complete the Create an API key tutorial and create an API key with the following privilege(s):

  2. Copy and paste the API key access token into a safe location. It will be used in a later step.

Create new OAuth credentials to access the secure resources used in this tutorial.

  1. Complete the Create OAuth credentials for user authentication tutorial to obtain a Client ID and Redirect URL.

    A Client ID uniquely identifies your app on the authenticating server. If the server cannot find an app with the provided Client ID, it will not proceed with authentication.

    The Redirect URL (also referred to as a callback url) is used to identify a response from the authenticating server when the system returns control back to your app after an OAuth login. Since it does not necessarily represent a valid endpoint that a user could navigate to, the redirect URL can use a custom scheme, such as my-app://auth. It is important to make sure the redirect URL used in your app's code matches a redirect URL configured on the authenticating server.

  2. Copy and paste the Client ID and Redirect URL into a safe location. They will be used in a later step.

All users that access this application need account privileges to access the ArcGIS Basemap Styles service and the ArcGIS Geocoding service.

Develop or Download

You have two options for completing this tutorial:

  1. Option 1: Develop the code or
  2. Option 2: Download the completed solution
Option 1: Develop the code

To start the tutorial, complete the Display a map tutorial. This creates a map to display the Santa Monica Mountains in California using the topographic basemap from the ArcGIS Basemap Styles service.

Continue with the following instructions search for places of interest, such as hotels, cafes, and gas stations using the ArcGIS Geocoding service. First, you need to set the develop credentials in your app so that you can access the ArcGIS Geocoding service.

Set developer credentials

If you implemented API key authentication in the Display a map tutorial, the API key access token will only have the Basemaps privilege. The Find places tutorial requires the Geocoding privilege to find places using the LocatorTask. To create an API Key access token that has the Basemaps and Geocoding privileges, see the Set up authentication step and then follow the instructions below.

Pass your API Key access token to the ArcGISEnvironment.

  1. In the Project Navigator, click MainApp.swift.

  2. Set the ArcGISEnvironment.apiKey property with your API key access token.

    MainApp.swift

    Use dark colors for code blocks

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
            ArcGISEnvironment.apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>")
    

Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

Use the Authenticator toolkit component to manage your OAuth credentials and pass it to the ArcGISEnvironment.

  1. In the Project Navigator, click MainApp.swift.

  2. Set your PortalURL, clientID and redirectURL values.

    MainApp.swift

    Use dark colors for code blocks

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
            authenticator = Authenticator(oAuthUserConfigurations: [
                OAuthUserConfiguration(
    
                    portalURL: URL(string: "<#YOUR-PORTAL-URL#>")!,
                    clientID: ""<#YOUR-CLIENT-ID#>"",
                    redirectURL: URL(string: "<#YOUR-REDIRECT-URL#>")!
    
                )
            ])
            ArcGISEnvironment.authenticationManager.handleChallenges(using: authenticator)
    

Best Practice: The OAuth credentials are stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

Update the map
  1. In Xcode, in the Project Navigator, click ContentView.swift.

  2. Create a private extension of ContentView and make a private class named Model of type ObservableObject. Add a @StateObject variable of the Model to the ContentView. See the programming patterns page for more information on how to manage states.

    ContentView.swift

    Use dark colors for code blocks

    18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 20 21 22 22 22 22 22 22 22 22 22 22 22 23 24 25 26 27 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 29 30 31 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 32 33 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 35 36 37

    Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    struct ContentView: View {
    
        @StateObject private var model = Model()
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
            return map
        }()
    
    }
    
    private extension ContentView {
    
        private class Model: ObservableObject {
    
        }
    
    }
  3. Create a GraphicsOverlay named graphicsOverlay in the 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.swift

    Use dark colors for code blocks

    134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 135 136 137 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 138 139 139 139

    Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        private class Model: ObservableObject {
    
            let graphicsOverlay = GraphicsOverlay()
    
        }
    
  4. Add the graphics overlay to the map view, wrap the map view inside a MapViewReader, and expose the MapViewProxy class in its closure. MapViewProxy provides operations that can be performed on the map view, such as 'identify'. For more information see Perform GeoView operations.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 44 43 42 41 40 39 38 37 35 33 31 29 27 25 23 21 19 18 17 16 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 15 16 17 18 18 18 18 18 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0 -1 -2 -3 -4 -5 -6 -6 -6 -7 -8 -9 -10 -11 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12 -12

    Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
            }
    
        }
    
Set up the LocatorTask

A locator task is used to search for places using a geocoding service. Results from this search contain the place location and additional information (attributes). Create the locator task along with any variables and methods needed to perform the search and display the results.

  1. In the Model, create a LocatorTask property named locator based on the Geocoding service.

    A locator task is used to convert an address to a point (geocode) or vice-versa (reverse geocode). An address includes any type of information that distinguishes a place. A locator involves finding matching locations for a given address. Reverse-geocoding is the opposite and finds the closest address for a given point.

    ContentView.swift

    Use dark colors for code blocks

    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 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 110 111 112 113 114 115 116 117 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 118 119 120 121

    Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    private extension ContentView {
    
        private class Model: ObservableObject {
    
            let graphicsOverlay = GraphicsOverlay()
    
            let locator = LocatorTask(
                url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")!
            )
    
        }
    
    }
  2. To support the geocode operation, create an enum named Category in the ContentView extension. Provide a String named "label" and a UIColor named "color". Each category is searched using its label and is distinguished on the map using its associated color.

    This tutorial uses category filtering to provide accurate search results based on pre-determined place categories. Feel free to modify this list to your specific requirements.

    ContentView.swift

    Use dark colors for code blocks

    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 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 143 144 145

    Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    private extension ContentView {
    
        enum Category: CaseIterable, Equatable {
            case coffeeShop, gasStation, food, hotel, parksOutdoors
    
            var label: String {
                switch self {
                case .coffeeShop: return "Coffee shop"
                case .gasStation: return "Gas station"
                case .food: return "Food"
                case .hotel: return "Hotel"
                case .parksOutdoors: return "Parks and Outdoors"
                }
            }
    
            var color: UIColor {
                switch self {
                case .coffeeShop: return .brown
                case .gasStation: return .orange
                case .food: return .purple
                case .hotel: return .blue
                case .parksOutdoors: return .green
                }
            }
        }
    
        private class Model: ObservableObject {
    
            let graphicsOverlay = GraphicsOverlay()
    
            let locator = LocatorTask(
                url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")!
            )
    
        }
    
    }
  3. In the ContentView struct, create a private variable named geoViewExtent of type Envelope with the @State property wrapper. This will be used to define the search location.

    ContentView.swift

    Use dark colors for code blocks

    18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 20 21 22 23 24 24 24 24 24 24 24 24 24 25 26 27 28 29 30 31 32 33 34 35 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 35 34 33 32 31 30 29 27 25 23 21 19 17 15 13 11 10 9 8 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 7 8 9 10 11 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 12 11 10 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 -19 -19 -19

    Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    struct ContentView: View {
    
        @StateObject private var model = Model()
    
        @State private var geoViewExtent: Envelope?
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
            return map
        }()
    
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
            }
    
        }
    
    }
    
  4. In the body, add the onVisibleAreaChanged(perform:) method to the map view. Set the geoViewExtent variable to the new visible area's extent.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 44 44 44 44 44 44 44 45 46 47 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 49 50 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51 51

    Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
                    .onVisibleAreaChanged { newVisibleArea in
                        geoViewExtent = newVisibleArea.extent
                    }
    
            }
    
        }
    
  5. In the Model, create a private, asynchronous method called findPlaces(forCategory:searchPoint:) to perform the geocode search operation. The method takes a parameter of type Category that you created in the previous step to indicate which category of places to search for and a Point that acts as the preferred search location.

    ContentView.swift

    Use dark colors for code blocks

    134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 134 135 136 137 138 139 140 141 142 143 144 144 144 144 144 144 144 144 144 143 142 141 140 139 138 137 136 135 134 133 132 131 130 129 129 129 129 129 130 131 132 132 132

    Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        private class Model: ObservableObject {
    
            let graphicsOverlay = GraphicsOverlay()
    
            let locator = LocatorTask(
                url: URL(string: "https://geocode-api.arcgis.com/arcgis/rest/services/World/GeocodeServer")!
            )
    
            func findPlaces(forCategory category: Category, searchPoint: Point? = nil) async {
    
            }
    
        }
    
  6. Clear the previous results by removing all graphics from the graphics overlay. Create and configure new GeocodeParameters. Populate them with the searchPoint parameter as the search location and add result attribute names.

    ContentView.swift

    Use dark colors for code blocks

    142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 143 144 145 146 147 148 149 149 149 149 148 147 146 145 144 143 142 141 140 139 138 137 136 135 134 134 134 134 134 135 135 135 135 135

    Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
            func findPlaces(forCategory category: Category, searchPoint: Point? = nil) async {
    
                graphicsOverlay.removeAllGraphics()
                let geocodeParameters = GeocodeParameters()
                geocodeParameters.preferredSearchLocation = searchPoint
                geocodeParameters.addResultAttributeNames(["Place_addr", "PlaceName"])
    
            }
    
  7. Perform the search query using geocode(forSearchText:using:). Pass in the category's label and the geocode parameters.

    ContentView.swift

    Use dark colors for code blocks

    142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 143 144 145 146 147 148 149 150 151 152 152 152 152 152 152 152 152 152 152 152 152 152 152 152 152 153 154 155 156 157 157 157 157 157

    Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
            func findPlaces(forCategory category: Category, searchPoint: Point? = nil) async {
    
                graphicsOverlay.removeAllGraphics()
                let geocodeParameters = GeocodeParameters()
                geocodeParameters.preferredSearchLocation = searchPoint
                geocodeParameters.addResultAttributeNames(["Place_addr", "PlaceName"])
    
                do {
                    let geocodeResults = try await locator.geocode(forSearchText: category.label, using: geocodeParameters)
    
                } catch {
                    print(error)
                }
    
            }
    
  8. Create graphics for each of the results and add them to the graphics overlay.

    ContentView.swift

    Use dark colors for code blocks

    142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 172 172 172 172

    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.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
            func findPlaces(forCategory category: Category, searchPoint: Point? = nil) async {
    
                graphicsOverlay.removeAllGraphics()
                let geocodeParameters = GeocodeParameters()
                geocodeParameters.preferredSearchLocation = searchPoint
                geocodeParameters.addResultAttributeNames(["Place_addr", "PlaceName"])
    
                do {
                    let geocodeResults = try await locator.geocode(forSearchText: category.label, using: geocodeParameters)
    
                    if !geocodeResults.isEmpty {
                        let placeSymbol = SimpleMarkerSymbol(
                            style: .circle,
                            color: category.color,
                            size: 10
                        )
                        placeSymbol.outline = SimpleLineSymbol(
                            style: .solid,
                            color: .white,
                            width: 2
                        )
                        let graphics = geocodeResults.map { Graphic(geometry: $0.displayLocation, attributes: $0.attributes, symbol: placeSymbol) }
                        graphicsOverlay.addGraphics(graphics)
                    }
    
                } catch {
                    print(error)
                }
    
            }
    
Add a category picker

You will add a Picker to the user interface to show categories of places to find, for example, coffee shops or gas stations. Each category will be displayed with a different color on the map.

  1. In the ContentView struct, add a variable of type Category with the @State property wrapper and give it a default value of coffeeShop. This will indicate the currently selected category.

    ContentView.swift

    Use dark colors for code blocks

    18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 20 21 22 23 24 25 26 26 26 26 26 26 26 27 28 29 30 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31

    Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    struct ContentView: View {
    
        @StateObject private var model = Model()
    
        @State private var geoViewExtent: Envelope?
    
        @State private var selectedCategory: Category = .coffeeShop
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
            return map
        }()
    
  2. In the ContentView body, add a toolbar view modifier to the map view that places a Toolbar at the bottom of the view where the Picker will be contained.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 44 44 44 44 44 44 44 45 46 47 48 48 48 48 48 48 48 48 48 47 46 45 44 43 42 41 39 37 35 33 31 29 27 25 23 22 21 20 19 19 19 20 21 22 22 22 22 22 22 22 22 22 22 22 22 23 24 25 26 27 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28 28

    Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
                    .onVisibleAreaChanged { newVisibleArea in
                        geoViewExtent = newVisibleArea.extent
                    }
    
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                        }
                    }
    
            }
    
        }
    
  3. Add a Picker to the toolbar and label it "Choose a category". Set the selection to $selectedCategory. This will iterate through .allCases of Category to populate the Picker with all the category labels. Add the .labelsHidden modifier.

    ContentView.swift

    Use dark colors for code blocks

    85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 64 62 60 58 56 54 52 49 46 43 40 37 34 31 28 25 23 21 19 17 16 15 16 17 18 19 20 21 22 23 24 25 25 25 25 25 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 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 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27 27

    Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                            Picker("Choose a category", selection: $selectedCategory) {
                                ForEach(Category.allCases, id: \.self) { category in
                                    Text(category.label)
                                }
                            }
                            .labelsHidden()
    
                        }
                    }
    
  4. Lastly, add a .task modifier to the Picker that calls the model's findPlaces(forCategory:searchPoint:) function. Pass in selectedCategory and the geoViewExtent?.center. This will initiate a geocode search when a category is selected.

    ContentView.swift

    Use dark colors for code blocks

    85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 84 83 82 81 80 79 78 77 76 75 74 73 72 71 70 69 68 67 66 64 62 60 58 56 54 52 49 46 43 40 37 34 31 28 25 23 21 19 17 16 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31 31

    Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                            Picker("Choose a category", selection: $selectedCategory) {
                                ForEach(Category.allCases, id: \.self) { category in
                                    Text(category.label)
                                }
                            }
                            .labelsHidden()
    
                            .task(id: selectedCategory) {
                                await model.findPlaces(forCategory: selectedCategory, searchPoint: geoViewExtent?.center)
                            }
    
                        }
                    }
    
Show information about a tapped location in the map

An identify operation can be used to get information about a geoelement (such as a graphic) at a location where the user has tapped on the map. A callout can be used to display this information.

  1. In the ContentView struct, add objects to track the map and screen locations. Create Point and CGPoint variables with the @State property wrappers. Name them mapLocation and tapLocation, respectively.

    ContentView.swift

    Use dark colors for code blocks

    18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 20 21 22 23 24 25 26 27 28 29 29 29 29 30 31 32 33 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34 34

    Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    struct ContentView: View {
    
        @StateObject private var model = Model()
    
        @State private var geoViewExtent: Envelope?
    
        @State private var selectedCategory: Category = .coffeeShop
    
        @State private var tapLocation: CGPoint?
        @State private var mapLocation: Point?
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
            return map
        }()
    
  2. Add objects to support the callout. Create CalloutPlacement and String variables with the @State property wrapper. Name them calloutPlacement and calloutText respectively.

    ContentView.swift

    Use dark colors for code blocks

    18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37 37

    Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    struct ContentView: View {
    
        @StateObject private var model = Model()
    
        @State private var geoViewExtent: Envelope?
    
        @State private var selectedCategory: Category = .coffeeShop
    
        @State private var tapLocation: CGPoint?
        @State private var mapLocation: Point?
    
        @State private var calloutPlacement: CalloutPlacement?
        @State private var calloutText: String?
    
        @State private var map = {
            let map = Map(basemapStyle: .arcGISTopographic)
            map.initialViewpoint = Viewpoint(latitude: 34.02700, longitude: -118.80500, scale: 72_000)
            return map
        }()
    
  3. In the body, add a .callout modifier to the map view. Pass in $calloutPlacement as the placement parameter. In the closure, create a Text object using the calloutText and provide a default String in case it is nil.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 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 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 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75

    Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
                    .callout(placement: $calloutPlacement.animation(.default.speed(2))) { _ in
                        Text(calloutText ?? "No address found.")
                            .font(.callout)
                            .padding(8)
                            .frame(maxWidth: 350)
                    }
    
                    .onVisibleAreaChanged { newVisibleArea in
                        geoViewExtent = newVisibleArea.extent
                    }
    
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                            Picker("Choose a category", selection: $selectedCategory) {
                                ForEach(Category.allCases, id: \.self) { category in
                                    Text(category.label)
                                }
                            }
                            .labelsHidden()
    
                            .task(id: selectedCategory) {
                                await model.findPlaces(forCategory: selectedCategory, searchPoint: geoViewExtent?.center)
                            }
    
                        }
                    }
    
            }
    
        }
    
  4. Add the onSingleTapGesture(perform:) method to the map view and set mapLocation and tapLocation.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80

    Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
                    .callout(placement: $calloutPlacement.animation(.default.speed(2))) { _ in
                        Text(calloutText ?? "No address found.")
                            .font(.callout)
                            .padding(8)
                            .frame(maxWidth: 350)
                    }
    
                    .onVisibleAreaChanged { newVisibleArea in
                        geoViewExtent = newVisibleArea.extent
                    }
    
                    .onSingleTapGesture { screenPoint, mapPoint in
                        tapLocation = screenPoint
                        mapLocation = mapPoint
                    }
    
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                            Picker("Choose a category", selection: $selectedCategory) {
                                ForEach(Category.allCases, id: \.self) { category in
                                    Text(category.label)
                                }
                            }
                            .labelsHidden()
    
                            .task(id: selectedCategory) {
                                await model.findPlaces(forCategory: selectedCategory, searchPoint: geoViewExtent?.center)
                            }
    
                        }
                    }
    
            }
    
        }
    
  5. Add a .task modifier to the map view, passing in tapLocation as the idefntifier. Ensure that the location objects are not nil.

    ContentView.swift

    Use dark colors for code blocks

    38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85 85

    Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
        var body: some View {
    
            MapViewReader { mapViewProxy in
    
                MapView(map: map, graphicsOverlays: [model.graphicsOverlay])
    
                    .callout(placement: $calloutPlacement.animation(.default.speed(2))) { _ in
                        Text(calloutText ?? "No address found.")
                            .font(.callout)
                            .padding(8)
                            .frame(maxWidth: 350)
                    }
    
                    .onVisibleAreaChanged { newVisibleArea in
                        geoViewExtent = newVisibleArea.extent
                    }
    
                    .onSingleTapGesture { screenPoint, mapPoint in
                        tapLocation = screenPoint
                        mapLocation = mapPoint
                    }
    
                    .task(id: tapLocation) {
                        guard let tapLocation, let mapLocation else { return }
    
                    }
    
                    .toolbar {
                        ToolbarItemGroup(placement: .bottomBar) {
    
                            Picker("Choose a category", selection: $selectedCategory) {
                                ForEach(Category.allCases, id: \.self) { category in
                                    Text(category.label)
                                }
                            }
                            .labelsHidden()
    
                            .task(id: selectedCategory) {
                                await model.findPlaces(forCategory: selectedCategory, searchPoint: geoViewExtent?.center)
                            }
    
                        }
                    }
    
            }
    
        }
    
  6. Perform identify(on:screenPoint:tolerance:returnPopupsOnly:maximumResults:) on the map view proxy to identify the graphics at the tapLocation.

    ContentView.swift

    Use dark colors for code blocks

    60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 61 62 63 64 65 66 67 68 69 70 70 70 70 70 70 70 70 70 70 71 72 73 74 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 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 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 75 75 75 75 75 75 75 75 75 75 75 75 75 75 75

    Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
                    .task(id: tapLocation) {
                        guard let tapLocation, let mapLocation else { return }
    
                        do {
                            let identifyResult = try await mapViewProxy.identify(
                                on: model.graphicsOverlay,
                                screenPoint: tapLocation,
                                tolerance: 12
                            )
    
                        } catch {
                            print(error)
                        }
    
                    }
    
  7. Lastly, assign the calloutText and calloutPlacement variables with with attributes from the first graphic of the identify results. This change in state will trigger the callout to be displayed.

    ContentView.swift

    Use dark colors for code blocks

    60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84 84

    Add line. Add line. Add line. Add line. Add line. Add line. Add line. Add line.
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
                    .task(id: tapLocation) {
                        guard let tapLocation, let mapLocation else { return }
    
                        do {
                            let identifyResult = try await mapViewProxy.identify(
                                on: model.graphicsOverlay,
                                screenPoint: tapLocation,
                                tolerance: 12
                            )
    
                            if let graphic = identifyResult.graphics.first {
                                let placeName = graphic.attributes["PlaceName"] as? String ?? "Unknown"
                                let placeAddress = graphic.attributes["Place_addr"] as? String ?? "no address provided"
                                calloutText = "\(placeName)\n\(placeAddress)"
                                calloutPlacement = .location(mapLocation)
                            } else {
                                calloutPlacement = nil
                            }
    
                        } catch {
                            print(error)
                        }
    
                    }
    
Run the solution

Press Command + R to run the app.

If you are using the Xcode simulator your system must meet these minimum requirements: macOS 14 (Sonoma), Xcode 16, iOS 18. If you are using a physical device, then refer to the system requirements.

When the app opens, use the picker to search different categories of places in the Malibu area near Los Angeles, California. You can tap one of the places and see its name and address.

Alternatively, you can download the tutorial solution, as follows.

Option 2: Download the solution
  1. Click the Download solution link under Solution and unzip the file to a location on your machine.

  2. Open the .xcodeproj file in Xcode.

Since the downloaded solution does not contain authentication credentials, you must add the developer credentials that you created in the Set up authentication section.

Set developer credentials in the solution

To allow your app users to access ArcGIS location services, use the developer credentials that you created in the Set up authentication step to authenticate requests for resources.

Pass your API Key access token to the ArcGISEnvironment.

  1. In the Project Navigator, click MainApp.swift.

  2. Set the AuthenticationMode to .apiKey.

    MainApp.swift

    Use dark colors for code blocks

    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
        // Change the `AuthenticationMode` to `.apiKey` if your application uses API key authentication.
    
        private var authenticationMode: AuthenticationMode { .apiKey }
    
    
  3. Set the apiKey property with your API key access token.

    MainApp.swift

    Expand

    Use dark colors for code blocks
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
        // Please enter an API key access token if your application uses API key authentication.
    
        private let apiKey = APIKey("<#YOUR-ACCESS-TOKEN#>")
    
    

Best Practice: The access token is stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

Use the Authenticator toolkit component to manage your OAuth credentials and pass it to the ArcGISEnvironment.

  1. In the Project Navigator, click MainApp.swift.

  2. Set the AuthenticationMode to .user.

    MainApp.swift

    Use dark colors for code blocks

    1
    2
    3
    // Change the `AuthenticationMode` to `.user` if your application uses OAuth credentials.
    
    private var authenticationMode: AuthenticationMode { .user }
  3. Set your portalURL, clientID and redirectURL values.

    MainApp.swift

    Expand

    Use dark colors for code blocks
    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
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
        // Setup an `Authenticator` with OAuth configuration if your application uses OAuth credentials.
        @ObservedObject var authenticator = Authenticator(
            oAuthUserConfigurations: [
                OAuthUserConfiguration(
    
                    // Please enter OAuth credentials for user authentication.
    
                    portalURL: URL(string: "<#YOUR-PORTAL-URL#>")!,
                    clientID: "<#YOUR-CLIENT-ID#>",
                    redirectURL: URL(string: "<#YOUR-REDIRECT-URL#>")!
    
                )
            ]
        )
    

Best Practice: The OAuth credentials are stored directly in the code as a convenience for this tutorial. Do not store credentials directly in source code in a production environment.

Run the solution

Press Command + R to run the app.

If you are using the Xcode simulator your system must meet these minimum requirements: macOS 14 (Sonoma), Xcode 16, iOS 18. If you are using a physical device, then refer to the system requirements.

When the app opens, use the picker to search different categories of places in the Malibu area near Los Angeles, California. You can tap one of the places and see its name and address.

What's next?

Learn how to use additional API features, ArcGIS location services, and ArcGIS tools in these tutorials:


RetroSearch is an open source project built by @garambo | Open a GitHub Issue

Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo

HTML: 3.2 | Encoding: UTF-8 | Version: 0.7.4