Before you begin coding, there are a few prerequisites that you'll need to set up.

Xcode

This tutorial uses Apple's Xcode tool, along with the Objective-C language to create a simple iOS application that runs in an emulator. You don't need a physical device. You can get Xcode at https://developer.apple.com/xcode/

CocoaPods

The Google Places API for iOS is available as a CocoaPods pod. CocoaPods is an open source dependency management tool for Swift and Objective-C projects. If you don't have this tool already, you'll need to install it before going any further. It can be installed from the terminal like this:

sudo gem install cocoapods

For more details on CocoaPods, see the CocoaPods Getting Started guide.

Installing the API

To install the API you need to create a Podfile in your project directory that CocoaPods will use to download and configure the requisite dependencies. The easiest way to do this is to create a new Project in Xcode, add a Podfile to that, and install the pods there.

Open Xcode and you'll see the ‘Welcome to Xcode' screen. On here, select ‘Create a new Xcode project'

On the next screen you'll be asked for a template for your new project. Select ‘Single View Application' for iOS, and press ‘Next'

When asked for the Product Name, you can choose anything you like, but be sure to note the Bundle Identifier that is generated for you. You'll need that later.

Press ‘Next' and the project will be created for you. Take a note of the directory where it is created. Close Xcode and using Terminal, navigate to that directory.

Using Terminal, enter the following command:

Pod init

A file called Podfile will be created for you. Edit it to add a pod for GoogleMaps like this:

target '{YOUR APP NAME}' do
pod 'GoogleMaps'
end

Save it, and close Xcode. Be sure to close it, because in the next step you are going to edit the underlying project. You'll be opening a different project file once it's done, and it's pretty common for a developer to get confused as to where everything is if they didn't previously close Xcode! Now, in a terminal, go to your project directory and run ‘pod install' like this:

Once you're done, the pods will be installed and a new .xcworkspace file will be created. Use this for the project from now on. But, before coding, the next thing you'll need is an API key

Your Places API Key will give you access to the Places API. You can get this by visiting the Google Places API for iOS site. On here you'll see a button that says ‘Get a Key'

When you press it, you'll get a dialog asking you to ‘Activate the Google Places API for iOS, detailing the steps:

Press ‘Continue' on this dialog. One of two things will happen. If you have an existing project on the Google Developers Console, you'll be able to select it, or add a new one.

Your project will be created and you'll be taken to a screen asking you to create an iOS API Key:

You'll need the bundle identifier that you created earlier -- for example ‘com.lmoroney.PlacesAPITest'. Enter it as shown, and press ‘Create'

Click Create, and you'll get a popup with an API key like this:

Take a note of this API key -- you'll be needing it when you write your app!

Now that you've created a console project, and activated the Places API on it, obtaining an API key, you're ready to begin coding your first Places API app.

Earlier when you installed the pod files, a new .xcworkspace file was created for you. Open this by double-clicking on it.

You'll notice in your Project Explorer that you now have a new folder called ‘Pods'. If this worked successfully, you'll see a GoogleMaps folder in there containing the frameworks.

When you first run the application, iOS will give you a dialog asking the user to give permission to access the location services. This dialog will give a string that you define, and you put it in the Info.plist file. If this string isn't present, the dialog won't show, and your app won't work.

You can find the Info.plist file in the project explorer here:

Select it, and you'll see the plist editor.

Hover the mouse over any of the elements, and you'll see a ‘+' icon appears. Press it, and you'll see a new entry appears. Enter the value ‘NSLocationAlwaysUsageDescription' in this box.

Press Enter to add the new key. Then double click the Value column for this key, and add a string:

To learn more about this string, see the apple developer documentation here.

In the project explorer, find and open AppDelegate.m. You'll use this to add your API Key.

At the top of the file, add this immediately below the #import line:

@import GoogleMaps;

Then, in the didFinishLaunchingWithOptions: function add the following just about the ‘return YES' line:

[GMSServices provideAPIKey:@"<Add your API Key>"];

Be sure to use the API Key that you generated earlier.

In the project explorer, open the Main.storyboard file. Make sure the side bar is active by pressing the sidebar button in the top right hand corner.

Then, at the bottom of the sidebar, find the Label Control by making sure the Object Library is selected.

In the View Controller Scene on the left hand side, make sure the ‘View' is selected:

Then drag and drop 7 labels onto the view. Arrange them as shown here. Be sure to drag their sizes to match what's shown. You can edit the text in the label by double clicking on it and typing the required value:

For the bottom most label (the really large one), go to the properties editor and ensure that it is set to have 0 lines (It defaults to 1). This will allow it to render multiple lines.

For the 3 ‘value' labels, you'll need to create an outlet. This will allow you to change their values using code. To do this, you'll first need to activate the assistant editor. To do this, first close the properties sidebar by clicking on its button to remove it. (This button was shown in the previous step)

Then, select the assistant button -- it's the double circle one shown here:

Make sure that it's rendering the ViewController.h file. If not, you can change it to do so using the editor at the top of the assistant window:

Then, when holding the CONTROL key, drag each label and drop it below the @interface line in the ViewController.h file in the assistant. A dialog will pop up asking what type of connection you want to make:

Make sure that the settings are as shown (Connection: Outlet; Type: UILabel; Storage: Weak), and then give each a name. For the purposes of this codelab, I called the Longitude, Latitude and Altitude labels lblLongitude, lblLatitude and lblAltidude respectively. Also drag the large label from the bottom over, and call it lblPlaces.

When you're done, your ViewController.h file should look like this:

#import <UIKit/UIKit.h>
@import GoogleMaps;

@interface ViewController : UIViewController
@property (weak, nonatomic) IBOutlet UILabel *lblLatitude;
@property (weak, nonatomic) IBOutlet UILabel *lblLongitude;
@property (weak, nonatomic) IBOutlet UILabel *lblAltitude;
@property (weak, nonatomic) IBOutlet UILabel *lblPlaces;

@end

Before the final steps -- where you build the app to use the places API you need to set up a few more variables in the header file (ViewController.h). These are the Core Location Manager and a Core Location object:

@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) CLLocation *location;

You'll also need a Google API Client:

@property GMSPlacesClient *placesClient;

Finally, you'll need to update the header file so that the class implements the CLLocationManagerDelegate:

@interface ViewController : UIViewController<CLLocationManagerDelegate>

When you're done, your header file should look this this:

#import <UIKit/UIKit.h>
#import <CoreLocation/CoreLocation.h>
#import <GoogleMaps/GoogleMaps.h>


@interface ViewController : UIViewController<CLLocationManagerDelegate>
@property (strong, nonatomic) CLLocationManager *locationManager;
@property (strong, nonatomic) CLLocation *location;
@property (weak, nonatomic) IBOutlet UILabel *lblLongitude;
@property (weak, nonatomic) IBOutlet UILabel *lblLatitude;
@property (weak, nonatomic) IBOutlet UILabel *lblAltitude;
@property (weak, nonatomic) IBOutlet UILabel *lblPlaces;

@property GMSPlacesClient *placesClient;
@end

The first step is to edit the viewDidLoad function to initialize the Location Manager, request the user's authorization to access location, and finally start the location manager so that it tracks the current location. You'll also initialize the Google Places API client.

- (void)viewDidLoad {
    [super viewDidLoad];
    self.locationManager = [[CLLocationManager alloc]init];
    self.locationManager.desiredAccuracy = kCLLocationAccuracyBest;
    if([self.locationManager respondsToSelector:@selector(requestAlwaysAuthorization)]) {
        [self.locationManager requestAlwaysAuthorization];
        // Or [self.locationManager requestWhenInUseAuthorization];
    }
    [self.locationManager startUpdatingLocation];
    
    self.locationManager.delegate = self;
    self.location = [[CLLocation alloc] init];
    self.placesClient = [GMSPlacesClient sharedClient];
}

The location manager will call back to your View Controller with location updates by calling the didUpdateLocations function. You'll need to add this to your ViewController.m. The function looks like this:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    // Enter code here
}

This function will need to do several things.

First, it will cache the location with the last received one:

self.location = locations.lastObject;

Next, the three labels for Latitude, Longitude and Altitude should be updated:

self.lblLatitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.latitude];

self.lblLongitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.longitude];

self.lblAltitude.text = [NSString stringWithFormat:@"%f", self.location.altitude];

Next you will call the Places API using the places Client. You do this by specifying the callback function, which will get the list of place likelihoods. The Places API determines the likelihood that you are in a particular place based on your location. It returns the name of likely places, along with a value between 0 and 1 containing the probability that you're in that place.

[self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

Then you can implement the callback. This will iterate through the list of likelihoods, adding places and likelihoods for those places.

[self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

  if (error != nil) {
    NSLog(@"Current Place error %@", [error localizedDescription]);
    return;
  }
  NSMutableString *strPlaces = [NSMutableString stringWithString:@""];

  for (GMSPlaceLikelihood *likelihood in likelihoodList.likelihoods) {
    GMSPlace* place = likelihood.place;
    NSLog(@"Current Place name %@ at likelihood %g", place.name,
            likelihood.likelihood);
    NSLog(@"Current Place address %@", place.formattedAddress);
    NSLog(@"Current Place attributions %@", place.attributions);
    NSLog(@"Current PlaceID %@", place.placeID);
    [strPlaces appendString:place.name];
    [strPlaces appendString:@" "];
    [strPlaces appendFormat:@"%g",likelihood.likelihood];
    [strPlaces appendString:@"\n"];
  }
  self.lblPlaces.text = strPlaces;
}];

When you're done, your didUpdateLocations function should look like this:

-(void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{
    
    self.location = locations.lastObject;
    self.lblLatitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.latitude];
    self.lblLongitude.text = [NSString stringWithFormat:@"%f", self.location.coordinate.longitude];
    self.lblAltitude.text = [NSString stringWithFormat:@"%f", self.location.altitude];
    
    NSLog(@"%@", self.location.description);
    
    [self.placesClient currentPlaceWithCallback:^(GMSPlaceLikelihoodList *likelihoodList, NSError *error) {

        if (error != nil) {
            NSLog(@"Current Place error %@", [error localizedDescription]);
            return;
        }
        NSMutableString *strPlaces = [NSMutableString stringWithString:@""];
        
        for (GMSPlaceLikelihood *likelihood in likelihoodList.likelihoods)  
        {
            GMSPlace* place = likelihood.place;
            NSLog(@"Current Place name %@ at likelihood %g", place.name, likelihood.likelihood);
            NSLog(@"Current Place address %@", place.formattedAddress);
            NSLog(@"Current Place attributions %@", place.attributions);
            NSLog(@"Current PlaceID %@", place.placeID);
            [strPlaces appendString:place.name];
            [strPlaces appendString:@" "];
            [strPlaces appendFormat:@"%g",likelihood.likelihood];
            [strPlaces appendString:@"\n"];
        }
        self.lblPlaces.text = strPlaces;
    }];
}

You're now ready to run your app and test it!

You run the app using the run button in the title bar. This also lets you select the run type, and as you can see here I'm testing on an iPhone 6, using the emulator.

When you press the run button, the app will build and launch. You'll see the request to allow the app to access location, including the custom string you specified earlier.

Once you do this, you'll see your Latitude and Longitude update. To change the location, select the Debug menu, and pick a location. For example, you can pick the ‘Freeway Drive'

When you do this, you'll see the location with its likely places updating, simulating the freeway drive.

And that's it! You've successfully accessed the current place details using the Google Places API on iOS.