Select Current Place and Show Details on a Map

This tutorial demonstrates building an iOS app that retrieves the device's current location, identifies likely locations, prompts the user to select the best match, and displays a map marker for the chosen location.

It's suitable for those with a beginning or intermediate knowledge of Swift or Objective-C and a general knowledge of Xcode. For an advanced guide to creating maps, read the developers' guide .

You'll create the following map using this tutorial. The map marker is positioned in San Francisco, California, but will move to wherever the device or simulator is located.

This tutorial uses the Places SDK for iOS , the Maps SDK for iOS , and the Apple Core Location framework .

Get the code

Clone or download Google Maps iOS samples repository from GitHub.

Alternatively, click the following button to download the source code:

Give me the code

MapViewController

Swift

 import 
  
 UIKit 
 import 
  
 GoogleMaps 
 import 
  
 GooglePlaces 
 class 
  
 MapViewController 
 : 
  
 UIViewController 
  
 { 
  
 var 
  
 locationManager 
 : 
  
 CLLocationManager 
 ! 
  
 var 
  
 currentLocation 
 : 
  
 CLLocation 
 ? 
  
 var 
  
 mapView 
 : 
  
 GMSMapView 
 ! 
  
 var 
  
 placesClient 
 : 
  
 GMSPlacesClient 
 ! 
  
 var 
  
 preciseLocationZoomLevel 
 : 
  
 Float 
  
 = 
  
 15.0 
  
 var 
  
 approximateLocationZoomLevel 
 : 
  
 Float 
  
 = 
  
 10.0 
  
 // An array to hold the list of likely places. 
  
 var 
  
 likelyPlaces 
 : 
  
 [ 
 GMSPlace 
 ] 
  
 = 
  
 [] 
  
 // The currently selected place. 
  
 var 
  
 selectedPlace 
 : 
  
 GMSPlace 
 ? 
  
 // 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 
  
 let 
  
 place 
  
 = 
  
 selectedPlace 
  
 { 
  
 let 
  
 marker 
  
 = 
  
 GMSMarker 
 ( 
 position 
 : 
  
 place 
 . 
 coordinate 
 ) 
  
 marker 
 . 
 title 
  
 = 
  
 selectedPlace 
 ?. 
 name 
  
 marker 
 . 
 snippet 
  
 = 
  
 selectedPlace 
 ?. 
 formattedAddress 
  
 marker 
 . 
 map 
  
 = 
  
 mapView 
  
 } 
  
 listLikelyPlaces 
 () 
  
 } 
  
 override 
  
 func 
  
 viewDidLoad 
 () 
  
 { 
  
 super 
 . 
 viewDidLoad 
 () 
  
 // Initialize the location manager. 
  
 locationManager 
  
 = 
  
 CLLocationManager 
 () 
  
 locationManager 
 . 
 desiredAccuracy 
  
 = 
  
 kCLLocationAccuracyBest 
  
 locationManager 
 . 
 requestWhenInUseAuthorization 
 () 
  
 locationManager 
 . 
 distanceFilter 
  
 = 
  
 50 
  
 locationManager 
 . 
 startUpdatingLocation 
 () 
  
 locationManager 
 . 
 delegate 
  
 = 
  
 self 
  
 placesClient 
  
 = 
  
 GMSPlacesClient 
 . 
 shared 
 () 
  
 // A default location to use when location permission is not granted. 
  
 let 
  
 defaultLocation 
  
 = 
  
 CLLocation 
 ( 
 latitude 
 : 
  
 - 
 33.869405 
 , 
  
 longitude 
 : 
  
 151.199 
 ) 
  
 // Create a map. 
  
 let 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 . 
 fullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
  
 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 
  
 listLikelyPlaces 
 () 
  
 } 
  
 // Populate the array with the list of likely places. 
  
 func 
  
 listLikelyPlaces 
 () 
  
 { 
  
 // Clean up from previous sessions. 
  
 likelyPlaces 
 . 
 removeAll 
 () 
  
 let 
  
 placeFields 
 : 
  
 GMSPlaceField 
  
 = 
  
 [. 
 name 
 , 
  
 . 
 coordinate 
 ] 
  
 placesClient 
 . 
 findPlaceLikelihoodsFromCurrentLocation 
 ( 
 withPlaceFields 
 : 
  
 placeFields 
 ) 
  
 { 
  
 ( 
 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 
 ) 
  
 } 
  
 } 
  
 } 
  
 // 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 
  
 } 
  
 } 
  
 } 
 } 
 // 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 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 . 
 fullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
  
 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 
 ) 
  
 { 
  
 // Check accuracy authorization 
  
 let 
  
 accuracy 
  
 = 
  
 manager 
 . 
 accuracyAuthorization 
  
 switch 
  
 accuracy 
  
 { 
  
 case 
  
 . 
 fullAccuracy 
 : 
  
 print 
 ( 
 "Location accuracy is precise." 
 ) 
  
 case 
  
 . 
 reducedAccuracy 
 : 
  
 print 
 ( 
 "Location accuracy is not precise." 
 ) 
  
 @ 
 unknown 
  
 default 
 : 
  
 fatalError 
 () 
  
 } 
  
 // Handle authorization status 
  
 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 
 ) 
 " 
 ) 
  
 } 
 } 
  

Objective-C

 #import "MapViewController.h" 
 #import "PlacesViewController.h" 
 @import 
  
 CoreLocation 
 ; 
 @import 
  
 GooglePlaces 
 ; 
 @import 
  
 GoogleMaps 
 ; 
 @interface 
 MapViewController 
  
 () 
  
< CLLocationManagerDelegate 
> @end 
 @implementation 
 MapViewController 
 { 
  
 CLLocationManager 
  
 * 
 locationManager 
 ; 
  
 CLLocation 
  
 * 
  
 _Nullable 
  
 currentLocation 
 ; 
  
 GMSMapView 
  
 * 
 mapView 
 ; 
  
 GMSPlacesClient 
  
 * 
 placesClient 
 ; 
  
 float 
  
 preciseLocationZoomLevel 
 ; 
  
 float 
  
 approximateLocationZoomLevel 
 ; 
  
 // An array to hold the list of likely places. 
  
 NSMutableArray<GMSPlace 
  
 * 
>  
 * 
 likelyPlaces 
 ; 
  
 // The currently selected place. 
  
 GMSPlace 
  
 * 
  
 _Nullable 
  
 selectedPlace 
 ; 
 } 
 - 
 ( 
 void 
 ) 
 viewDidLoad 
  
 { 
  
 [ 
 super 
  
 viewDidLoad 
 ]; 
  
 preciseLocationZoomLevel 
  
 = 
  
 15.0 
 ; 
  
 approximateLocationZoomLevel 
  
 = 
  
 15.0 
 ; 
  
 // Initialize the location manager. 
  
 locationManager 
  
 = 
  
 [[ 
 CLLocationManager 
  
 alloc 
 ] 
  
 init 
 ]; 
  
 locationManager 
 . 
 desiredAccuracy 
  
 = 
  
 kCLLocationAccuracyBest 
 ; 
  
 [ 
 locationManager 
  
 requestWhenInUseAuthorization 
 ]; 
  
 locationManager 
 . 
 distanceFilter 
  
 = 
  
 50 
 ; 
  
 [ 
 locationManager 
  
 startUpdatingLocation 
 ]; 
  
 locationManager 
 . 
 delegate 
  
 = 
  
 self 
 ; 
  
 placesClient 
  
 = 
  
 [ 
 GMSPlacesClient 
  
 sharedClient 
 ]; 
  
 // A default location to use when location permission is not granted. 
  
 CLLocationCoordinate2D 
  
 defaultLocation 
  
 = 
  
 CLLocationCoordinate2DMake 
 ( 
 -33.869405 
 , 
  
 151.199 
 ); 
  
 // Create a map. 
  
 float 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 CLAccuracyAuthorizationFullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
 ; 
  
 GMSCameraPosition 
  
 * 
 camera 
  
 = 
  
 [ 
 GMSCameraPosition 
  
 cameraWithLatitude 
 : 
 defaultLocation 
 . 
 latitude 
  
 longitude 
 : 
 defaultLocation 
 . 
 longitude 
  
 zoom 
 : 
 zoomLevel 
 ]; 
  
 mapView 
  
 = 
  
 [ 
 GMSMapView 
  
 mapWithFrame 
 : 
 self 
 . 
 view 
 . 
 bounds 
  
 camera 
 : 
 camera 
 ]; 
  
 mapView 
 . 
 settings 
 . 
 myLocationButton 
  
 = 
  
 YES 
 ; 
  
 mapView 
 . 
 autoresizingMask 
  
 = 
  
 UIViewAutoresizingFlexibleWidth 
  
 | 
  
 UIViewAutoresizingFlexibleHeight 
 ; 
  
 mapView 
 . 
 myLocationEnabled 
  
 = 
  
 YES 
 ; 
  
 // Add the map to the view, hide it until we've got a location update. 
  
 [ 
 self 
 . 
 view 
  
 addSubview 
 : 
 mapView 
 ]; 
  
 mapView 
 . 
 hidden 
  
 = 
  
 YES 
 ; 
  
 [ 
 self 
  
 listLikelyPlaces 
 ]; 
 } 
 // Populate the array with the list of likely places. 
 - 
 ( 
 void 
 ) 
 listLikelyPlaces 
 { 
  
 // Clean up from previous sessions. 
  
 likelyPlaces 
  
 = 
  
 [ 
 NSMutableArray 
  
 array 
 ]; 
  
 GMSPlaceField 
  
 placeFields 
  
 = 
  
 GMSPlaceFieldName 
  
 | 
  
 GMSPlaceFieldCoordinate 
 ; 
  
 [ 
 placesClient 
  
 findPlaceLikelihoodsFromCurrentLocationWithPlaceFields 
 : 
 placeFields 
  
 callback 
 :^ 
 ( 
 NSArray<GMSPlaceLikelihood 
  
 * 
>  
 * 
  
 _Nullable 
  
 likelihoods 
 , 
  
 NSError 
  
 * 
  
 _Nullable 
  
 error 
 ) 
  
 { 
  
 if 
  
 ( 
 error 
  
 != 
  
 nil 
 ) 
  
 { 
  
 // TODO: Handle the error. 
  
 NSLog 
 ( 
 @"Current Place error: %@" 
 , 
  
 error 
 . 
 localizedDescription 
 ); 
  
 return 
 ; 
  
 } 
  
 if 
  
 ( 
 likelihoods 
  
 == 
  
 nil 
 ) 
  
 { 
  
 NSLog 
 ( 
 @"No places found." 
 ); 
  
 return 
 ; 
  
 } 
  
 for 
  
 ( 
 GMSPlaceLikelihood 
  
 * 
 likelihood 
  
 in 
  
 likelihoods 
 ) 
  
 { 
  
 GMSPlace 
  
 * 
 place 
  
 = 
  
 likelihood 
 . 
 place 
 ; 
  
 [ 
 likelyPlaces 
  
 addObject 
 : 
 place 
 ]; 
  
 } 
  
 }]; 
 } 
 // Update the map once the user has made their selection. 
 - 
 ( 
 void 
 ) 
 unwindToMain: 
 ( 
 UIStoryboardSegue 
  
 * 
 ) 
 segue 
 { 
  
 // Clear the map. 
  
 [ 
 mapView 
  
 clear 
 ]; 
  
 // Add a marker to the map. 
  
 if 
  
 ( 
 selectedPlace 
  
 != 
  
 nil 
 ) 
  
 { 
  
 GMSMarker 
  
 * 
 marker 
  
 = 
  
 [ 
 GMSMarker 
  
 markerWithPosition 
 : 
 selectedPlace 
 . 
 coordinate 
 ]; 
  
 marker 
 . 
 title 
  
 = 
  
 selectedPlace 
 . 
 name 
 ; 
  
 marker 
 . 
 snippet 
  
 = 
  
 selectedPlace 
 . 
 formattedAddress 
 ; 
  
 marker 
 . 
 map 
  
 = 
  
 mapView 
 ; 
  
 } 
  
 [ 
 self 
  
 listLikelyPlaces 
 ]; 
 } 
 // Prepare the segue. 
 - 
 ( 
 void 
 ) 
 prepareForSegue: 
 ( 
 UIStoryboardSegue 
  
 * 
 ) 
 segue 
  
 sender: 
 ( 
 id 
 ) 
 sender 
 { 
  
 if 
  
 ([ 
 segue 
 . 
 identifier 
  
 isEqualToString 
 : 
 @"segueToSelect" 
 ]) 
  
 { 
  
 if 
  
 ([ 
 segue 
 . 
 destinationViewController 
  
 isKindOfClass 
 : 
 [ 
 PlacesViewController 
  
 class 
 ]]) 
  
 { 
  
 PlacesViewController 
  
 * 
 placesViewController 
  
 = 
  
 ( 
 PlacesViewController 
  
 * 
 ) 
 segue 
 . 
 destinationViewController 
 ; 
  
 placesViewController 
 . 
 likelyPlaces 
  
 = 
  
 likelyPlaces 
 ; 
  
 } 
  
 } 
 } 
 // Delegates to handle events for the location manager. 
 #pragma mark - CLLocationManagerDelegate 
 // Handle incoming location events. 
 - 
 ( 
 void 
 ) 
 locationManager: 
 ( 
 CLLocationManager 
  
 * 
 ) 
 manager 
  
 didUpdateLocations: 
 ( 
 NSArray<CLLocation 
  
 * 
>  
 * 
 ) 
 locations 
 { 
  
 CLLocation 
  
 * 
 location 
  
 = 
  
 locations 
 . 
 lastObject 
 ; 
  
 NSLog 
 ( 
 @"Location: %@" 
 , 
  
 location 
 ); 
  
 float 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 CLAccuracyAuthorizationFullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
 ; 
  
 GMSCameraPosition 
  
 * 
  
 camera 
  
 = 
  
 [ 
 GMSCameraPosition 
  
 cameraWithLatitude 
 : 
 location 
 . 
 coordinate 
 . 
 latitude 
  
 longitude 
 : 
 location 
 . 
 coordinate 
 . 
 longitude 
  
 zoom 
 : 
 zoomLevel 
 ]; 
  
 if 
  
 ( 
 mapView 
 . 
 isHidden 
 ) 
  
 { 
  
 mapView 
 . 
 hidden 
  
 = 
  
 NO 
 ; 
  
 mapView 
 . 
 camera 
  
 = 
  
 camera 
 ; 
  
 } 
  
 else 
  
 { 
  
 [ 
 mapView 
  
 animateToCameraPosition 
 : 
 camera 
 ]; 
  
 } 
  
 [ 
 self 
  
 listLikelyPlaces 
 ]; 
 } 
 // Handle authorization for the location manager. 
 - 
 ( 
 void 
 ) 
 locationManager: 
 ( 
 CLLocationManager 
  
 * 
 ) 
 manager 
  
 didChangeAuthorizationStatus: 
 ( 
 CLAuthorizationStatus 
 ) 
 status 
 { 
  
 // Check accuracy authorization 
  
 CLAccuracyAuthorization 
  
 accuracy 
  
 = 
  
 manager 
 . 
 accuracyAuthorization 
 ; 
  
 switch 
  
 ( 
 accuracy 
 ) 
  
 { 
  
 case 
  
 CLAccuracyAuthorizationFullAccuracy 
 : 
  
 NSLog 
 ( 
 @"Location accuracy is precise." 
 ); 
  
 break 
 ; 
  
 case 
  
 CLAccuracyAuthorizationReducedAccuracy 
 : 
  
 NSLog 
 ( 
 @"Location accuracy is not precise." 
 ); 
  
 break 
 ; 
  
 } 
  
 // Handle authorization status 
  
 switch 
  
 ( 
 status 
 ) 
  
 { 
  
 case 
  
 kCLAuthorizationStatusRestricted 
 : 
  
 NSLog 
 ( 
 @"Location access was restricted." 
 ); 
  
 break 
 ; 
  
 case 
  
 kCLAuthorizationStatusDenied 
 : 
  
 NSLog 
 ( 
 @"User denied access to location." 
 ); 
  
 // Display the map using the default location. 
  
 mapView 
 . 
 hidden 
  
 = 
  
 NO 
 ; 
  
 case 
  
 kCLAuthorizationStatusNotDetermined 
 : 
  
 NSLog 
 ( 
 @"Location status not determined." 
 ); 
  
 case 
  
 kCLAuthorizationStatusAuthorizedAlways 
 : 
  
 case 
  
 kCLAuthorizationStatusAuthorizedWhenInUse 
 : 
  
 NSLog 
 ( 
 @"Location status is OK." 
 ); 
  
 } 
 } 
 // Handle location manager errors. 
 - 
 ( 
 void 
 ) 
 locationManager: 
 ( 
 CLLocationManager 
  
 * 
 ) 
 manager 
  
 didFailWithError: 
 ( 
 NSError 
  
 * 
 ) 
 error 
 { 
  
 [ 
 manager 
  
 stopUpdatingLocation 
 ]; 
  
 NSLog 
 ( 
 @"Error: %@" 
 , 
  
 error 
 . 
 localizedDescription 
 ); 
 } 
 @end 
  

PlacesViewController

Swift

 import 
  
 UIKit 
 import 
  
 GooglePlaces 
 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 
 ) 
  
 } 
  
 // 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 
  
 } 
 } 
 // 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 
  
 } 
 } 
  

Objective-C

 #import "PlacesViewController.h" 
 @interface 
 PlacesViewController 
  
 () 
  
< UITableViewDataSource 
 , 
  
 UITableViewDelegate 
> // ... 
 - 
 ( 
 void 
 ) 
 prepareForSegue 
 : 
 ( 
 UIStoryboardSegue 
  
 * 
 ) 
 segue 
  
 sender 
 : 
 ( 
 id 
 ) 
 sender 
 { 
 } 
 #pragma mark - UITableViewDelegate 
 // Respond when a user selects a place. 
 - 
 ( 
 void 
 ) 
 tableView 
 : 
 ( 
 UITableView 
  
 * 
 ) 
 tableView 
  
 didSelectRowAtIndexPath 
 : 
 ( 
 NSIndexPath 
  
 * 
 ) 
 indexPath 
 { 
  
 self 
 . 
 selectedPlace 
  
 = 
  
 [ 
 self 
 . 
 likelyPlaces 
  
 objectAtIndex 
 : 
 indexPath 
 . 
 row 
 ]; 
  
 [ 
 self 
  
 performSegueWithIdentifier 
 : 
 @"unwindToMain" 
  
 sender 
 : 
 self 
 ]; 
 } 
 // Adjust cell height to only show the first five items in the table 
 // (scrolling is disabled in IB). 
 - 
 ( 
 CGFloat 
 ) 
 tableView 
 : 
 ( 
 UITableView 
  
 * 
 ) 
 tableView 
  
 heightForRowAtIndexPath 
 : 
 ( 
 NSIndexPath 
  
 * 
 ) 
 indexPath 
 { 
  
 return 
  
 self 
 . 
 tableView 
 . 
 frame 
 . 
 size 
 . 
 height 
 / 
 5 
 ; 
 } 
 // Make table rows display at proper height if there are less than 5 items. 
 - 
 ( 
 CGFloat 
 ) 
 tableView 
 : 
 ( 
 UITableView 
  
 * 
 ) 
 tableView 
  
 heightForFooterInSection 
 : 
 ( 
 NSInteger 
 ) 
 section 
 { 
  
 if 
  
 ( 
 section 
  
 == 
  
 tableView 
 . 
 numberOfSections 
  
 - 
  
 1 
 ) 
  
 { 
  
 return 
  
 1 
 ; 
  
 } 
  
 return 
  
 0 
 ; 
 } 
 #pragma mark - UITableViewDataSource 
 - 
  
 ( 
 NSInteger 
 ) 
 tableView 
 : 
 ( 
 UITableView 
  
 * 
 ) 
 tableView 
  
 numberOfRowsInSection 
 : 
 ( 
 NSInteger 
 ) 
 section 
 { 
  
 return 
  
 self 
 . 
 likelyPlaces 
 . 
 count 
 ; 
 } 
 - 
  
 ( 
 UITableViewCell 
  
 * 
 ) 
 tableView 
 : 
 ( 
 UITableView 
  
 * 
 ) 
 tableView 
  
 cellForRowAtIndexPath 
 : 
 ( 
 NSIndexPath 
  
 * 
 ) 
 indexPath 
 { 
  
 return 
  
 [ 
 tableView 
  
 dequeueReusableCellWithIdentifier 
 : 
 cellReuseIdentifier 
  
 forIndexPath 
 : 
 indexPath 
 ]; 
 } 
 @end 
  

Get started

Swift Package Manager

The Maps SDK for iOS can be installed using Swift Package Manager .

  1. Remove any existing Maps SDK for iOS dependencies.
  2. Open a terminal window and navigate to the tutorials/current-place-on-map directory.
  3. Close your Xcode workspace and run the following commands:
      
     sudo 
      
     gem 
      
     install 
      
     cocoapods 
     - 
     deintegrate 
      
     cocoapods 
     - 
     clean 
      
     pod 
      
     deintegrate 
      
     pod 
      
     cache 
      
     clean 
      
     -- 
     all 
      
     rm 
      
     Podfile 
      
     rm 
      
     current 
     - 
     place 
     - 
     on 
     - 
     map 
     . 
     xcworkspace 
    
  4. Open your Xcode project and delete the podfile.
  5. Add the Places and Maps SDKs:
    1. Go to File > Add Package Dependencies .
    2. Enter https://github.com/googlemaps/ios-places-sdk as the URL, press Enter to pull in the package, and click Add Package .
    3. Enter https://github.com/googlemaps/ios-maps-sdk as the URL, press Enter to pull in the package, and click Add Package .
  6. You may need to reset your package cache using File > Packages > Reset Package Cache .

Use CocoaPods

  1. Download and install Xcode version 16.0or later.
  2. If you don't already have CocoaPods , install it on macOS by running the following command from the terminal:
    sudo gem install cocoapods
  3. Navigate to the tutorials/current-place-on-map directory.
  4. Run the pod install command. This will install the Maps and Places SDKs specified in the Podfile , along with any dependencies.
  5. Run pod outdated to compare the installed pod version with any new updates. If a new version is detected, run pod update to update the Podfile and install the latest SDK. For more details, see the CocoaPods Guide .
  6. Open (double-click) the project's current-place-on-map.xcworkspacefile to open it in Xcode. You must use the .xcworkspace file to open the project.

Get an API key and enable the necessary APIs

To complete this tutorial, you need a Google API key that's authorized to use the Maps SDK for iOSand 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. Note that following import statement has been added to the file:
     import 
      
     GooglePlaces 
     import 
      
     GoogleMaps 
    
  2. Edit the following line in 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 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 Featuresmenu.
  3. In Xcode, click the Product/Runmenu 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.

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.
  • If you have restricted the API key by the iOS bundle identifier, edit the key to add the bundle identifier for the app: com.google.examples.current-place-on-map .
  • The map won't 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.
  • Make sure that you have a good Wi-Fi 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-mapapp, to help you understand how to build a similar app.

The current-place-on-mapapp features two view controllers: One to display a map showing the user's 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 .

Requesting 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. Swift

     var 
      
     locationManager 
     : 
      
     CLLocationManager 
     ! 
     var 
      
     currentLocation 
     : 
      
     CLLocation 
     ? 
     var 
      
     mapView 
     : 
      
     GMSMapView 
     ! 
     var 
      
     placesClient 
     : 
      
     GMSPlacesClient 
     ! 
     var 
      
     preciseLocationZoomLevel 
     : 
      
     Float 
      
     = 
      
     15.0 
     var 
      
     approximateLocationZoomLevel 
     : 
      
     Float 
      
     = 
      
     10.0 
      
    

    Objective-C

     CLLocationManager 
      
     * 
     locationManager 
     ; 
     CLLocation 
      
     * 
      
     _Nullable 
      
     currentLocation 
     ; 
     GMSMapView 
      
     * 
     mapView 
     ; 
     GMSPlacesClient 
      
     * 
     placesClient 
     ; 
     float 
      
     preciseLocationZoomLevel 
     ; 
     float 
      
     approximateLocationZoomLevel 
     ; 
      
    
  3. Initialize the location manager and GMSPlacesClient in viewDidLoad() .
  4. Swift

     // Initialize the location manager. 
     locationManager 
      
     = 
      
     CLLocationManager 
     () 
     locationManager 
     . 
     desiredAccuracy 
      
     = 
      
     kCLLocationAccuracyBest 
     locationManager 
     . 
     requestWhenInUseAuthorization 
     () 
     locationManager 
     . 
     distanceFilter 
      
     = 
      
     50 
     locationManager 
     . 
     startUpdatingLocation 
     () 
     locationManager 
     . 
     delegate 
      
     = 
      
     self 
     placesClient 
      
     = 
      
     GMSPlacesClient 
     . 
     shared 
     () 
      
    

    Objective-C

     // Initialize the location manager. 
     locationManager 
      
     = 
      
     [[ 
     CLLocationManager 
      
     alloc 
     ] 
      
     init 
     ]; 
     locationManager 
     . 
     desiredAccuracy 
      
     = 
      
     kCLLocationAccuracyBest 
     ; 
     [ 
     locationManager 
      
     requestWhenInUseAuthorization 
     ]; 
     locationManager 
     . 
     distanceFilter 
      
     = 
      
     50 
     ; 
     [ 
     locationManager 
      
     startUpdatingLocation 
     ]; 
     locationManager 
     . 
     delegate 
      
     = 
      
     self 
     ; 
     placesClient 
      
     = 
      
     [ 
     GMSPlacesClient 
      
     sharedClient 
     ]; 
      
    
  5. Declare variables to hold the list of likely places, and the user's selected place.
  6. Swift

     // An array to hold the list of likely places. 
     var 
      
     likelyPlaces 
     : 
      
     [ 
     GMSPlace 
     ] 
      
     = 
      
     [] 
     // The currently selected place. 
     var 
      
     selectedPlace 
     : 
      
     GMSPlace 
     ? 
      
    

    Objective-C

     // An array to hold the list of likely places. 
     NSMutableArray<GMSPlace 
      
     * 
    >  
     * 
     likelyPlaces 
     ; 
     // The currently selected place. 
     GMSPlace 
      
     * 
      
     _Nullable 
      
     selectedPlace 
     ; 
      
    
  7. Add delegates to handle events for the location manager, using an extension clause.
  8. Swift

     // 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 
      
     zoomLevel 
      
     = 
      
     locationManager 
     . 
     accuracyAuthorization 
      
     == 
      
     . 
     fullAccuracy 
      
     ? 
      
     preciseLocationZoomLevel 
      
     : 
      
     approximateLocationZoomLevel 
      
     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 
     ) 
      
     { 
      
     // Check accuracy authorization 
      
     let 
      
     accuracy 
      
     = 
      
     manager 
     . 
     accuracyAuthorization 
      
     switch 
      
     accuracy 
      
     { 
      
     case 
      
     . 
     fullAccuracy 
     : 
      
     print 
     ( 
     "Location accuracy is precise." 
     ) 
      
     case 
      
     . 
     reducedAccuracy 
     : 
      
     print 
     ( 
     "Location accuracy is not precise." 
     ) 
      
     @ 
     unknown 
      
     default 
     : 
      
     fatalError 
     () 
      
     } 
      
     // Handle authorization status 
      
     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 
     ) 
     " 
     ) 
      
     } 
     } 
      
    

    Objective-C

     // Delegates to handle events for the location manager. 
     #pragma mark - CLLocationManagerDelegate 
     // Handle incoming location events. 
     - 
     ( 
     void 
     ) 
     locationManager: 
     ( 
     CLLocationManager 
      
     * 
     ) 
     manager 
      
     didUpdateLocations: 
     ( 
     NSArray<CLLocation 
      
     * 
    >  
     * 
     ) 
     locations 
     { 
      
     CLLocation 
      
     * 
     location 
      
     = 
      
     locations 
     . 
     lastObject 
     ; 
      
     NSLog 
     ( 
     @"Location: %@" 
     , 
      
     location 
     ); 
      
     float 
      
     zoomLevel 
      
     = 
      
     locationManager 
     . 
     accuracyAuthorization 
      
     == 
      
     CLAccuracyAuthorizationFullAccuracy 
      
     ? 
      
     preciseLocationZoomLevel 
      
     : 
      
     approximateLocationZoomLevel 
     ; 
      
     GMSCameraPosition 
      
     * 
      
     camera 
      
     = 
      
     [ 
     GMSCameraPosition 
      
     cameraWithLatitude 
     : 
     location 
     . 
     coordinate 
     . 
     latitude 
      
     longitude 
     : 
     location 
     . 
     coordinate 
     . 
     longitude 
      
     zoom 
     : 
     zoomLevel 
     ]; 
      
     if 
      
     ( 
     mapView 
     . 
     isHidden 
     ) 
      
     { 
      
     mapView 
     . 
     hidden 
      
     = 
      
     NO 
     ; 
      
     mapView 
     . 
     camera 
      
     = 
      
     camera 
     ; 
      
     } 
      
     else 
      
     { 
      
     [ 
     mapView 
      
     animateToCameraPosition 
     : 
     camera 
     ]; 
      
     } 
      
     [ 
     self 
      
     listLikelyPlaces 
     ]; 
     } 
     // Handle authorization for the location manager. 
     - 
     ( 
     void 
     ) 
     locationManager: 
     ( 
     CLLocationManager 
      
     * 
     ) 
     manager 
      
     didChangeAuthorizationStatus: 
     ( 
     CLAuthorizationStatus 
     ) 
     status 
     { 
      
     // Check accuracy authorization 
      
     CLAccuracyAuthorization 
      
     accuracy 
      
     = 
      
     manager 
     . 
     accuracyAuthorization 
     ; 
      
     switch 
      
     ( 
     accuracy 
     ) 
      
     { 
      
     case 
      
     CLAccuracyAuthorizationFullAccuracy 
     : 
      
     NSLog 
     ( 
     @"Location accuracy is precise." 
     ); 
      
     break 
     ; 
      
     case 
      
     CLAccuracyAuthorizationReducedAccuracy 
     : 
      
     NSLog 
     ( 
     @"Location accuracy is not precise." 
     ); 
      
     break 
     ; 
      
     } 
      
     // Handle authorization status 
      
     switch 
      
     ( 
     status 
     ) 
      
     { 
      
     case 
      
     kCLAuthorizationStatusRestricted 
     : 
      
     NSLog 
     ( 
     @"Location access was restricted." 
     ); 
      
     break 
     ; 
      
     case 
      
     kCLAuthorizationStatusDenied 
     : 
      
     NSLog 
     ( 
     @"User denied access to location." 
     ); 
      
     // Display the map using the default location. 
      
     mapView 
     . 
     hidden 
      
     = 
      
     NO 
     ; 
      
     case 
      
     kCLAuthorizationStatusNotDetermined 
     : 
      
     NSLog 
     ( 
     @"Location status not determined." 
     ); 
      
     case 
      
     kCLAuthorizationStatusAuthorizedAlways 
     : 
      
     case 
      
     kCLAuthorizationStatusAuthorizedWhenInUse 
     : 
      
     NSLog 
     ( 
     @"Location status is OK." 
     ); 
      
     } 
     } 
     // Handle location manager errors. 
     - 
     ( 
     void 
     ) 
     locationManager: 
     ( 
     CLLocationManager 
      
     * 
     ) 
     manager 
      
     didFailWithError: 
     ( 
     NSError 
      
     * 
     ) 
     error 
     { 
      
     [ 
     manager 
      
     stopUpdatingLocation 
     ]; 
      
     NSLog 
     ( 
     @"Error: %@" 
     , 
      
     error 
     . 
     localizedDescription 
     ); 
     } 
      
    

Adding 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).

Swift

 // A default location to use when location permission is not granted. 
 let 
  
 defaultLocation 
  
 = 
  
 CLLocation 
 ( 
 latitude 
 : 
  
 - 
 33.869405 
 , 
  
 longitude 
 : 
  
 151.199 
 ) 
 // Create a map. 
 let 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 . 
 fullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
 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 
  

Objective-C

 // A default location to use when location permission is not granted. 
 CLLocationCoordinate2D 
  
 defaultLocation 
  
 = 
  
 CLLocationCoordinate2DMake 
 ( 
 -33.869405 
 , 
  
 151.199 
 ); 
 // Create a map. 
 float 
  
 zoomLevel 
  
 = 
  
 locationManager 
 . 
 accuracyAuthorization 
  
 == 
  
 CLAccuracyAuthorizationFullAccuracy 
  
 ? 
  
 preciseLocationZoomLevel 
  
 : 
  
 approximateLocationZoomLevel 
 ; 
 GMSCameraPosition 
  
 * 
 camera 
  
 = 
  
 [ 
 GMSCameraPosition 
  
 cameraWithLatitude 
 : 
 defaultLocation 
 . 
 latitude 
  
 longitude 
 : 
 defaultLocation 
 . 
 longitude 
  
 zoom 
 : 
 zoomLevel 
 ]; 
 mapView 
  
 = 
  
 [ 
 GMSMapView 
  
 mapWithFrame 
 : 
 self 
 . 
 view 
 . 
 bounds 
  
 camera 
 : 
 camera 
 ]; 
 mapView 
 . 
 settings 
 . 
 myLocationButton 
  
 = 
  
 YES 
 ; 
 mapView 
 . 
 autoresizingMask 
  
 = 
  
 UIViewAutoresizingFlexibleWidth 
  
 | 
  
 UIViewAutoresizingFlexibleHeight 
 ; 
 mapView 
 . 
 myLocationEnabled 
  
 = 
  
 YES 
 ; 
 // Add the map to the view, hide it until we've got a location update. 
 [ 
 self 
 . 
 view 
  
 addSubview 
 : 
 mapView 
 ]; 
 mapView 
 . 
 hidden 
  
 = 
  
 YES 
 ; 
  

Prompting 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 located.
  2. Swift

     // Populate the array with the list of likely places. 
     func 
      
     listLikelyPlaces 
     () 
      
     { 
      
     // Clean up from previous sessions. 
      
     likelyPlaces 
     . 
     removeAll 
     () 
      
     let 
      
     placeFields 
     : 
      
     GMSPlaceField 
      
     = 
      
     [. 
     name 
     , 
      
     . 
     coordinate 
     ] 
      
     placesClient 
     . 
     findPlaceLikelihoodsFromCurrentLocation 
     ( 
     withPlaceFields 
     : 
      
     placeFields 
     ) 
      
     { 
      
     ( 
     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 
     ) 
      
     } 
      
     } 
     } 
      
    

    Objective-C

     // Populate the array with the list of likely places. 
     - 
     ( 
     void 
     ) 
     listLikelyPlaces 
     { 
      
     // Clean up from previous sessions. 
      
     likelyPlaces 
      
     = 
      
     [ 
     NSMutableArray 
      
     array 
     ]; 
      
     GMSPlaceField 
      
     placeFields 
      
     = 
      
     GMSPlaceFieldName 
      
     | 
      
     GMSPlaceFieldCoordinate 
     ; 
      
     [ 
     placesClient 
      
     findPlaceLikelihoodsFromCurrentLocationWithPlaceFields 
     : 
     placeFields 
      
     callback 
     :^ 
     ( 
     NSArray<GMSPlaceLikelihood 
      
     * 
    >  
     * 
      
     _Nullable 
      
     likelihoods 
     , 
      
     NSError 
      
     * 
      
     _Nullable 
      
     error 
     ) 
      
     { 
      
     if 
      
     ( 
     error 
      
     != 
      
     nil 
     ) 
      
     { 
      
     // TODO: Handle the error. 
      
     NSLog 
     ( 
     @"Current Place error: %@" 
     , 
      
     error 
     . 
     localizedDescription 
     ); 
      
     return 
     ; 
      
     } 
      
     if 
      
     ( 
     likelihoods 
      
     == 
      
     nil 
     ) 
      
     { 
      
     NSLog 
     ( 
     @"No places found." 
     ); 
      
     return 
     ; 
      
     } 
      
     for 
      
     ( 
     GMSPlaceLikelihood 
      
     * 
     likelihood 
      
     in 
      
     likelihoods 
     ) 
      
     { 
      
     GMSPlace 
      
     * 
     place 
      
     = 
      
     likelihood 
     . 
     place 
     ; 
      
     [ 
     likelyPlaces 
      
     addObject 
     : 
     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. Swift

     // 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 
      
     } 
      
     } 
     } 
      
    

    Objective-C

     // Prepare the segue. 
     - 
     ( 
     void 
     ) 
     prepareForSegue: 
     ( 
     UIStoryboardSegue 
      
     * 
     ) 
     segue 
      
     sender: 
     ( 
     id 
     ) 
     sender 
     { 
      
     if 
      
     ([ 
     segue 
     . 
     identifier 
      
     isEqualToString 
     : 
     @"segueToSelect" 
     ]) 
      
     { 
      
     if 
      
     ([ 
     segue 
     . 
     destinationViewController 
      
     isKindOfClass 
     : 
     [ 
     PlacesViewController 
      
     class 
     ]]) 
      
     { 
      
     PlacesViewController 
      
     * 
     placesViewController 
      
     = 
      
     ( 
     PlacesViewController 
      
     * 
     ) 
     segue 
     . 
     destinationViewController 
     ; 
      
     placesViewController 
     . 
     likelyPlaces 
      
     = 
      
     likelyPlaces 
     ; 
      
     } 
      
     } 
     } 
      
    
  5. In PlacesViewController , fill the table using the list of most likely places, using the UITableViewDataSource delegate extension.
  6. Swift

     // 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 
      
     } 
     } 
      
    

    Objective-C

     #pragma mark - UITableViewDataSource 
     - 
     ( 
     NSInteger 
     ) 
     tableView: 
     ( 
     UITableView 
      
     * 
     ) 
     tableView 
      
     numberOfRowsInSection: 
     ( 
     NSInteger 
     ) 
     section 
     { 
      
     return 
      
     self 
     . 
     likelyPlaces 
     . 
     count 
     ; 
     } 
     - 
     ( 
     UITableViewCell 
      
     * 
     ) 
     tableView: 
     ( 
     UITableView 
      
     * 
     ) 
     tableView 
      
     cellForRowAtIndexPath: 
     ( 
     NSIndexPath 
      
     * 
     ) 
     indexPath 
     { 
      
     return 
      
     [ 
     tableView 
      
     dequeueReusableCellWithIdentifier 
     : 
     cellReuseIdentifier 
      
     forIndexPath 
     : 
     indexPath 
     ]; 
     } 
     @end 
      
    
  7. Handle the user's selection using the UITableViewDelegate delegate extension.
  8. Swift

     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 
     ) 
      
     } 
      
     // 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 
      
     } 
     } 
      
    

    Objective-C

     @interface 
     PlacesViewController 
      
     () 
      
    < UITableViewDataSource 
     , 
      
     UITableViewDelegate 
    > // ... 
     - 
     ( 
     void 
     ) 
     prepareForSegue 
     : 
     ( 
     UIStoryboardSegue 
      
     * 
     ) 
     segue 
      
     sender 
     : 
     ( 
     id 
     ) 
     sender 
     { 
     } 
     #pragma mark - UITableViewDelegate 
     // Respond when a user selects a place. 
     - 
     ( 
     void 
     ) 
     tableView 
     : 
     ( 
     UITableView 
      
     * 
     ) 
     tableView 
      
     didSelectRowAtIndexPath 
     : 
     ( 
     NSIndexPath 
      
     * 
     ) 
     indexPath 
     { 
      
     self 
     . 
     selectedPlace 
      
     = 
      
     [ 
     self 
     . 
     likelyPlaces 
      
     objectAtIndex 
     : 
     indexPath 
     . 
     row 
     ]; 
      
     [ 
     self 
      
     performSegueWithIdentifier 
     : 
     @"unwindToMain" 
      
     sender 
     : 
     self 
     ]; 
     } 
     // Adjust cell height to only show the first five items in the table 
     // (scrolling is disabled in IB). 
     - 
     ( 
     CGFloat 
     ) 
     tableView 
     : 
     ( 
     UITableView 
      
     * 
     ) 
     tableView 
      
     heightForRowAtIndexPath 
     : 
     ( 
     NSIndexPath 
      
     * 
     ) 
     indexPath 
     { 
      
     return 
      
     self 
     . 
     tableView 
     . 
     frame 
     . 
     size 
     . 
     height 
     / 
     5 
     ; 
     } 
     // Make table rows display at proper height if there are less than 5 items. 
     - 
     ( 
     CGFloat 
     ) 
     tableView 
     : 
     ( 
     UITableView 
      
     * 
     ) 
     tableView 
      
     heightForFooterInSection 
     : 
     ( 
     NSInteger 
     ) 
     section 
     { 
      
     if 
      
     ( 
     section 
      
     == 
      
     tableView 
     . 
     numberOfSections 
      
     - 
      
     1 
     ) 
      
     { 
      
     return 
      
     1 
     ; 
      
     } 
      
     return 
      
     0 
     ; 
     } 
      
    

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.

Swift

 // 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 
  
 let 
  
 place 
  
 = 
  
 selectedPlace 
  
 { 
  
 let 
  
 marker 
  
 = 
  
 GMSMarker 
 ( 
 position 
 : 
  
 place 
 . 
 coordinate 
 ) 
  
 marker 
 . 
 title 
  
 = 
  
 selectedPlace 
 ?. 
 name 
  
 marker 
 . 
 snippet 
  
 = 
  
 selectedPlace 
 ?. 
 formattedAddress 
  
 marker 
 . 
 map 
  
 = 
  
 mapView 
  
 } 
  
 listLikelyPlaces 
 () 
 } 
  

Objective-C

 // Update the map once the user has made their selection. 
 - 
 ( 
 void 
 ) 
 unwindToMain: 
 ( 
 UIStoryboardSegue 
  
 * 
 ) 
 segue 
 { 
  
 // Clear the map. 
  
 [ 
 mapView 
  
 clear 
 ]; 
  
 // Add a marker to the map. 
  
 if 
  
 ( 
 selectedPlace 
  
 != 
  
 nil 
 ) 
  
 { 
  
 GMSMarker 
  
 * 
 marker 
  
 = 
  
 [ 
 GMSMarker 
  
 markerWithPosition 
 : 
 selectedPlace 
 . 
 coordinate 
 ]; 
  
 marker 
 . 
 title 
  
 = 
  
 selectedPlace 
 . 
 name 
 ; 
  
 marker 
 . 
 snippet 
  
 = 
  
 selectedPlace 
 . 
 formattedAddress 
 ; 
  
 marker 
 . 
 map 
  
 = 
  
 mapView 
 ; 
  
 } 
  
 [ 
 self 
  
 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 .

Create a Mobile Website
View Site in Mobile | Classic
Share by: