It's the 15th anniversary of Google Maps Platform - Check out the latest news and announcements

Select Current Place and Show Details on a Map

This tutorial shows you how to build an iOS app to:

  • Get the current device location.
  • Get a list of places where the device is likely to be located.
  • Prompt the user for the best place match.
  • Show a marker on the map.

Follow this tutorial to build an iOS app using the Places SDK for iOS, the Maps SDK for iOS, and the Apple Core Location framework.

Get the code

Clone or download the Google Maps SDK for iOS from GitHub.

Set up your development project

Follow these steps to install the Places SDK for iOS and the Maps SDK for iOS:

  1. Download and install Xcode.
  2. If you don't already have the CocoaPods tool, install it on macOS by running the following command from the terminal:
    sudo gem install cocoapods
  3. In the directory where you saved the sample repository (Get the code), navigate to the tutorials/current-place-on-map directory.
  4. Run the pod install command. This installs the APIs specified in the Podfile, along with any dependencies they may have.
  5. Open current-place-on-map.xcworkspace in Xcode.

For detailed installation instructions, see Getting Started (Maps), and Getting Started (Places).

Enable the necessary APIs and get an API key

To complete this tutorial, you need a Google API key that's authorized to use the Maps SDK for iOS and the Places API.

  1. Follow the instructions on Get Started with Google Maps Platform to set up a billing account and a project enabled with both of these products.
  2. Follow the instructions on Get an API Key to create an API key for the development project you set up previously.

Add the API key to your application

Add your API key to your AppDelegate.swift as follows:

  1. Add the following import statements:
    import GooglePlaces
    import GoogleMaps
  2. Add the following to your application(_:didFinishLaunchingWithOptions:) method, replacing YOUR_API_KEY with your API key:
    GMSPlacesClient.provideAPIKey("YOUR_API_KEY")
    GMSServices.provideAPIKey("YOUR_API_KEY")

Build and run your app

  1. Connect an iOS device to your computer, or select a simulator from the Xcode scheme pop-up menu.
  2. If you're using a device, make sure that location services are enabled. If you're using a simulator, select a location from the Debug/Location menu.
  3. In Xcode, click the Product/Run menu option (or the play button icon).

Xcode builds the app, and then runs the app on the device or on the simulator.

You should see a map with a number of markers centered around your current location, similar to the image on this page.

Troubleshooting:

  • If you don't see a map, check that you've obtained an API key and added it to the app, as described above. Check Xcode's debugging console for error messages about the API key.
  • The map will not display properly if the permissions request for location services is declined.
    • If you're using a device, go to Settings/General/Privacy/Location Services, and re-enable location services.
    • If you're using a simulator, go to Simulator/Reset Content and Settings...
    The next time the app is run, be sure to accept the location services prompt.
  • Ensure that you have a good WiFi or GPS connection.
  • If the app launches but no map is displayed, make sure that you have updated the Info.plist for your project with the appropriate location permissions. For more information about permissions handling, see the guide to requesting location permission in your app below.
  • Use the Xcode debugging tools to view logs and debug the app.

Understand the code

This part of the tutorial explains the most significant parts of the current-place-on-map app, to help you understand how to build a similar app.

The current-place-on-map app features two view controllers: One to display a map showing the user's currently selected place, and one to present the user with a list of likely places to choose from. Note that each view controller has the same variables for tracking the list of likely places (likelyPlaces), and for indicating the user's selection (selectedPlace). Navigation between views is accomplished by using segues.

Request location permission

Your app must prompt the user for consent to use location services. To do this, include the NSLocationAlwaysUsageDescription key in the Info.plist file for the app, and set the value of each key to a string that describes how the app intends to use location data.

Set up the location manager

Use CLLocationManager to find the device's current location and to request regular updates when the device moves to a new location. This tutorial provides the code you need to get the device's location. For more details, see the guide to Getting the User's Location in the Apple Developer Documentation.

  1. Declare the location manager, current location, map view, places client, and default zoom level at the class level.
  2.   var locationManager: CLLocationManager!
      var currentLocation: CLLocation?
      var mapView: GMSMapView!
      var placesClient: GMSPlacesClient!
      var zoomLevel: Float = 15.0
    
  3. Initialize the location manager and GMSPlacesClient in viewDidLoad().
  4.     // Initialize the location manager.
        locationManager = CLLocationManager()
        locationManager.desiredAccuracy = kCLLocationAccuracyBest
        locationManager.requestAlwaysAuthorization()
        locationManager.distanceFilter = 50
        locationManager.startUpdatingLocation()
        locationManager.delegate = self
    
        placesClient = GMSPlacesClient.shared()
    
  5. Declare variables to hold the list of likely places, and the user's selected place.
  6.   // An array to hold the list of likely places.
      var likelyPlaces: [GMSPlace] = []
    
      // The currently selected place.
      var selectedPlace: GMSPlace?
    
  7. Add delegates to handle events for the location manager, using an extension clause.
  8. // Delegates to handle events for the location manager.
    extension MapViewController: CLLocationManagerDelegate {
    
      // Handle incoming location events.
      func locationManager(_ manager: CLLocationManager, didUpdateLocations locations: [CLLocation]) {
        let location: CLLocation = locations.last!
        print("Location: \(location)")
    
        let camera = GMSCameraPosition.camera(withLatitude: location.coordinate.latitude,
                                              longitude: location.coordinate.longitude,
                                              zoom: zoomLevel)
    
        if mapView.isHidden {
          mapView.isHidden = false
          mapView.camera = camera
        } else {
          mapView.animate(to: camera)
        }
    
        listLikelyPlaces()
      }
    
      // Handle authorization for the location manager.
      func locationManager(_ manager: CLLocationManager, didChangeAuthorization status: CLAuthorizationStatus) {
        switch status {
        case .restricted:
          print("Location access was restricted.")
        case .denied:
          print("User denied access to location.")
          // Display the map using the default location.
          mapView.isHidden = false
        case .notDetermined:
          print("Location status not determined.")
        case .authorizedAlways: fallthrough
        case .authorizedWhenInUse:
          print("Location status is OK.")
        @unknown default:
          fatalError()
        }
      }
    
      // Handle location manager errors.
      func locationManager(_ manager: CLLocationManager, didFailWithError error: Error) {
        locationManager.stopUpdatingLocation()
        print("Error: \(error)")
      }
    }
    

Add a map

  • Create a map and add it to the view in viewDidLoad() in the main view controller. The map stays hidden until a location update is received (location updates are handled in the CLLocationManagerDelegate extension).
  •     // Create a map.
        let camera = GMSCameraPosition.camera(withLatitude: defaultLocation.coordinate.latitude,
                                              longitude: defaultLocation.coordinate.longitude,
                                              zoom: zoomLevel)
        mapView = GMSMapView.map(withFrame: view.bounds, camera: camera)
        mapView.settings.myLocationButton = true
        mapView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
        mapView.isMyLocationEnabled = true
    
        // Add the map to the view, hide it until we've got a location update.
        view.addSubview(mapView)
        mapView.isHidden = true
    

Prompt the user to select their current place

Use the Places SDK for iOS to get the top five place likelihoods based on the user's current location, and present the list in a UITableView. When the user selects a place, add a marker to the map.

  1. Get a list of likely places to populate a UITableView, from which the user can select the place where they are currently located.
  2.   // Populate the array with the list of likely places.
      func listLikelyPlaces() {
        // Clean up from previous sessions.
        likelyPlaces.removeAll()
    
        placesClient.findPlaceLikelihoodsFromCurrentLocation(withPlaceFields: .name) { (placeLikelihoods, error) in
          guard error == nil else {
            // TODO: Handle the error.
            print("Current Place error: \(error!.localizedDescription)")
            return
          }
    
          guard let placeLikelihoods = placeLikelihoods else {
            print("No places found.")
            return
          }
          
          // Get likely places and add to the list.
          for likelihood in placeLikelihoods {
            let place = likelihood.place
            self.likelyPlaces.append(place)
          }
        }
      }
    
  3. Open a new view to present likely places to the user. When the user taps "Get Place", we segue to a new view, and show the user a list of possible places to choose from. The prepare function updates PlacesViewController with the list of current likely places, and is automatically called when a segue is performed.
  4.   // Prepare the segue.
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "segueToSelect" {
          if let nextViewController = segue.destination as? PlacesViewController {
            nextViewController.likelyPlaces = likelyPlaces
          }
        }
      }
    
  5. In PlacesViewController, fill the table using the list of most likely places, using the UITableViewDataSource delegate extension.
  6. // Populate the table with the list of most likely places.
    extension PlacesViewController: UITableViewDataSource {
      func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return likelyPlaces.count
      }
    
      func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: cellReuseIdentifier, for: indexPath)
        let collectionItem = likelyPlaces[indexPath.row]
    
        cell.textLabel?.text = collectionItem.name
    
        return cell
      }
    
      // Adjust cell height to only show the first five items in the table
      // (scrolling is disabled in IB).
      func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        return self.tableView.frame.size.height/5
      }
    
      // Make table rows display at proper height if there are less than 5 items.
      func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        if (section == tableView.numberOfSections - 1) {
          return 1
        }
        return 0
      }
    }
    
  7. Handle the user's selection using the UITableViewDelegate delegate extension.
  8. class PlacesViewController: UIViewController {
    
      // ...
    
      // Pass the selected place to the new view controller.
      override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "unwindToMain" {
          if let nextViewController = segue.destination as? MapViewController {
            nextViewController.selectedPlace = selectedPlace
          }
        }
      }
    }
    
    // Respond when a user selects a place.
    extension PlacesViewController: UITableViewDelegate {
      func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        selectedPlace = likelyPlaces[indexPath.row]
        performSegue(withIdentifier: "unwindToMain", sender: self)
      }
    }
    

Add a marker to the map

  • When the user makes a selection, use an unwind segue to return to the previous view, and add the marker to the map. The unwindToMain IBAction is called automatically upon returning to the main view controller.
  •   // Update the map once the user has made their selection.
      @IBAction func unwindToMain(segue: UIStoryboardSegue) {
        // Clear the map.
        mapView.clear()
    
        // Add a marker to the map.
        if selectedPlace != nil {
          let marker = GMSMarker(position: (self.selectedPlace?.coordinate)!)
          marker.title = selectedPlace?.name
          marker.snippet = selectedPlace?.formattedAddress
          marker.map = mapView
        }
    
        listLikelyPlaces()
      }
    

Congratulations! You've built an iOS app that lets the user choose their current place, and shows the result on a Google map. In the course of doing this, you've learned how to use the Places SDK for iOS, the Maps SDK for iOS, and the Apple Core Location framework.