Google Places for iOS 5 SDK

I am integrating the Google Places API into an iPhone app that I am building.  I found an existing library that uses Google Local Search but that is deprecated.  So I forked that solution and came up with Google Places Library.

As the story goes…when the application is configured to allow current location, the fun begins.

First configure your project to include the CoreLocation and the MapKit framework.  I am using a single view project for this example but it can be any project really.

In the RootViewController I need to define some delegates.  Since I will be embedding a UITableView and UISearchBar I need the following to be added: <UITextFieldDelegate, UITableViewDelegate, UITableViewDataSource, UISearchBarDelegate, CLLocationManagerDelegate, GooglePlacesConnectionDelegate>

UITableViewDelegate – will help populate the data on my table.

UISearchBarDelegate – will perform some interactions with the searching of places

CLLocationManagerDelegate – will get the location

GooglePlacesConnectionDelegate – will perform the main search

Once that is complete I can then add some outlets for my UI and set up some properties.

Lets move on to the meat and potatoes of this app.  Within the .m file I need to initialize some of my variables and get the GoogleConnection going.

Do not forget to set the url connection to nil in the viewDidUnload.

Lets move to the Location Manager methods.

The first one returns a location manager or creates one if necessary

The next method really starts the fun. In my case I am constructing a URL for the Google Places API. If you are not familiar with it you can find more about it here. The url takes the following parameters:

  • key: required – your API key
  • location: required – latitude/longitude around which to retrieve Place information. Location manager will help here
  • radius: required – distance in meters. For the initial search I have 500, for the UISearchBar I moved it out to 1000.
  • sensor: required – needs to be set to TRUE if came from a device with a location sensor
  • keyword: optional – a term to be matched if searching
  • language: optional – language codes
  • name: optional – term to be matched against the names of the Places
  • types: narrows the search to a specific type of place. Here is a list

At the end of all of this the url will look like this:

https://maps.googleapis.com/maps/api/place/search/json?location=-33.8670522,151.1957362&radius=500&types=food&name=harbour&sensor=false&key=AIzaSyAiFpFd85eMtfbvmVNEYuNds5TEF9FjIPI

The last methods are the setting of the objects and some clean up.

I am not going to dive deep into the GooglePlacesConnection class or the GooglePlacesObject. However I will say this, the GooglePlacesObject is just that. An object of the Google Place. It has an init that will take the dictionary object from the JSON results. The GooglePlacesConnection does the work of constructing of the URL and issuing the request. One thing to note, the only error checking on the Google Place request is if there are 0 results or an error with the URL or request. There are other status codes if you want to add them in if needed.

Back into the RootViewController.m, we now should have a locations NSMutableArray so we can now populate our UITableView.

We set the count of the array to the number of rows in section. We then get the locations object at the indexPath and set that to a GooglePlacesObject and populate the cell.

To handle the UISeachBar here is the code:

The second, third and fourth method handle the interaction with the UISearchBar itself. Each calls the updateSearchString method and passes in the text from the search bar. updateSearchString performs a similar search to the location manager search, except it is passing in the search string as well. If you look in the GooglePlacesConnection method I am also expanding the search radius to 1000 from 500.

That is it. You can find the source on github.

My next update will be adding a ‘pull to refresh’.

57 Comments

  1. Hello Joshua,

    I’m new with google places api.

    Just downloaded your app sample. After build and run, I’m getting this message. Thread 1: Program received signal: “SIGABRT”. Do I need to change something to see the result?

    Thanks,
    Vuthy Ray

    Reply
    • I just updated the solution on Github. There was an issue with the rootviewcontroller.xib file. I decided to move it over to a Storyboard.

      Also – remember to get an API key from google and update the key in GooglePlacesObject.h file

      Reply
  2. Hello Joshua,

    Is it possible to set the table results to a certain location with a preset category? For an example, I live in Atlanta Ga. this would be my current location. Than as for the category, it would be (kBank) in the table results.

    Thanks,

    Reply
    • Yes. It is possible. The LocationManager does the work of finding your Lat/Lng. Basically if you want to just have one location you would not need that. The GooglePlacesConnection methods you would use and ‘hard code’ the Lat/Lng for Atlanta in there. Start by removing the LocationManager and instead of calling it from the ViewDidLoad method call the GooglePlacesConnection method instead.

      Reply
  3. Hello Joshua,

    I been trying to analyze your ViewController.m file. Xcode returned this message “Value stored to ‘place’ during its initialization is never read”.

    This is where it pointed to:

    // Get the object to display and set the value in the cell.
    GooglePlacesObject *place = [[GooglePlacesObject alloc] init];
    place = [locations objectAtIndex:[indexPath row]];

    Any idea to fix this?

    Reply
    • I’m not getting that. Are you sure you have the api key in there? Also, are you sure you are getting results back?

      As far as the Map goes, not right now. I need to finish phase one of this app first. Phase 2 has mapping in it.

      Reply
  4. Hello Joshua,

    As I far as I know, I believed that I have the right API key from Google. Should I request for a new one?

    Yes, I’m getting some of the results, but not all the places near me. For an example: kGrocerySupermarket will not give me Walmart Super Center at all. I even set the radius to 50000. Still no result. But kStore will. The only problem with it, its also given me Home Depot as well. Which is not a supermarket type. I has checked with Google for support on this, but I have not found any.

    Thank you for your updates.

    Reply
    • If you can, take the full url that is being built, put it in your browser to make sure there is no syntax error.

      I am using this for restaurants and I have noticed that not all of them in my area show up. The only thing that I can think of is that they are all not ‘tagged’ correctly. So for my restaurants i am using pubs, bars, cafes etc.. to make sure a full list comes back.

      Reply
  5. Hey Josh,

    Thanks for this very helpful tutorial. I’m developing an iPhone app that will use the Google Places API.

    Before that I used the Google Local Search API from this guy ( https://github.com/vvanhee/Google-Local-Search-iOS ), It worked very well for displaying on map the google searches.

    I’m trying to do the same with your classes, but without success until now. When I do:

    [map addAnnotations:objects]

    the map doesn’t add any annotation :-(

    (“objects” is the array with the GooglePlacesObject’s the service returns to me)

    I tried to add the annotations one by one to the map, but I figured out that the coordinates of the GooglePlacesObject’s doesn’t exists? Is there a way to get them throught the api ?

    Or do you have an idea on how I could change your code to get the coordinate for a GooglePlacesObject? I think it’s because of that the map cannot display the annotations.

    Much thanks for your help.

    Regards,

    Jon

    Reply
    • I think I see what is going on. I quickly stepped through the code and the lat and long are both 0 when it is being set in the places object. I will try to get an update soon. Might be a typo or the json parser is not finding it.

      Reply
  6. Hello Joshua,

    I have a basic question. On this line of code (static NSString *CellIdentifier =@”LocationCell”;). Xcode is complaining about it. So I set “LocationCell” in the Table View Cell under Identifier:Reuse Identifier to match it. Now the subtitle (address) won’t show at all. Please help.

    Thanks,

    Reply
  7. It a warning. I did not change any of your original code at all.
    This is what I did: In the storyboard, I entered LocationCell in the table View Cell Identifier as show in your screen grab. Still not showing the subtitle. Do you think there something wrong with my Xcode version? Version 4.2.1. And thank you for the new update.

    Reply
    • You should be able to get those values from the GooglePlacesObject. In your cellForRowAtIndexPath method you will need to create additional labels or concat the text into one label. Depending upon your design.

      Reply
  8. Thanks for your quick reply.

    Yes, I tried creating a new label as follow:

    cell.textLabel.text=place.formattedPhoneNumber;

    Returned blank result. I even tried with your original .m by replacing cell.detailTextLable.text=place.vicinity; with cell.detailTextLable.text=place.formattedPhoneNumber;

    Still nothing.

    Have you try it?

    Reply
  9. Take a look at the Google Places API. Phone number does not come back with the place request. You would have to issue a place details request to get that.

    Reply
    • You might want to get a new pull from GitHub. I added a few more things. PullToRefresh the table view. Detail View of the selected Place and a map.

      Reply
  10. Hello Joshua,

    The new update look GREAT. Now come another idea and problem. In the detail view I changed the UILabel website to formattedPhoneNumber. Its work find, but than I added a UIButton to make a phone call from it. Its also seen to be working, but it not a valid phone number when it dial. Here the code I used:

    -(IBAction)callPhone:(id)sender
    {

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:@"tel:placePhoneNumber"]];
    }

    Any idea?

    Reply
  11. Got it to work for me now.

    Here the code:

    NSString *telephoneString=[placePhoneNumber.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];

    NSMutableString *str1=[[NSMutableString alloc] initWithString:telephoneString];
    [str1 setString:[str1 stringByReplacingOccurrencesOfString:@"(" withString:@""]];
    [str1 setString:[str1 stringByReplacingOccurrencesOfString:@")" withString:@""]];
    [str1 setString:[str1 stringByReplacingOccurrencesOfString:@"-" withString:@""]];
    [str1 setString:[str1 stringByReplacingOccurrencesOfString:@" " withString:@""]];
    telephoneString = [@"tel://" stringByAppendingString:str1];

    [[UIApplication sharedApplication] openURL:[NSURL URLWithString:telephoneString]];

    Reply
    • Can you please kindly aware me that where this code should be placed to place phone call….. sorry I am not a advanced programmer……..every thing is being setup except this code….thanks in advance

      Reply
  12. Problem converting to ARC with this line GTMCFAutorelease(escaped)

    - (NSString*)gtm_stringByEscapingForURLArgument {
    // Encode all the reserved characters, per RFC 3986
    // ()
    CFStringRef escaped =
    CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault,
    (CFStringRef)self,
    NULL,
    (CFStringRef)@”!*’();:@&=+$,/?%#[]“,
    kCFStringEncodingUTF8);
    return GTMCFAutorelease(escaped);
    }

    Reply
  13. great article!

    do you have any tips on getting the image thumbnails from the GooglePlacesObject? Is this possible?

    I’d like to have them display in the table row cells.

    thanks in advance

    Reply
  14. This is a great example. Thank you, I would like to know where in this example you set the radius? I would like to increase it.

    Thank you.

    Reply
    • I found the answer. It is in googleplacesconnection.m .

      This is a great example. Thank you, I would like to know where in this example you set the radius? I would like to increase it.

      Thank you.

      Reply
      • yes, in the googleplacesconnection.m

        NSString* gurl = [NSString stringWithFormat:@"https://maps.googleapis.com/maps/api/place/search/json?location=%f,%f&radius=500i&types=%@&sensor=true&key=",
        centerLat, centerLng, types, kGOOGLE_API_KEY];

        Reply
  15. I have entered my google API key into the project, but when I run I still get the message “The operation couldn’t be completed. (GoogleLocalObjectDomain error 500.) I noticed someone above had this same issue. What am I doing wrong? Please help : )

    Reply
  16. If you look in GooglePlaces.h file there is a constant called kGOOGLE_API_KEY. Please put your google api key in there. Do not put it in googleplacesconnection, you can but it defeats the purpose of the constant. the only other config that you might want is the radius which in in the string for the gurl in the GooglePlacesConnection.m file

    Reply
  17. Joshua,

    This is an AWESOME piece of work and exactly what I was looking for. I got my googlekey and have successfully built your app ‘as is’ (running on all the latest Xcode and IOS) successfully on both the desktop and my 4S.

    I’m a newbie, and have two questions

    I’m modifying your code by adding a storyboard screen called “ChosenVendorViewController” subclassed to your “DetailViewController”. This new page is to ‘mimic’ passing information from the “DetailViewController” to a new page. I added a ‘uibutton’ to your “DetailViewController” page to navigate to my new “ChosenVendorViewController” page. Navigation works fine with no errors. I’ve added 3 labels to the “ChosenVendorController” page which I plan to pass some of the location information to from your “DetailViewController” page.

    1) Immediately after building the subclass for my new page (ChosenVendorViewController) in order to get my *h and *.m files, when I navigate from your DetailViewController page to my new ChosenVendorViewController page, I get a ‘popup’:

    Error finding place – Try again
    The operation couldn’t be completed
    (GoogleLocalObjectDomain error
    500.)

    It acts like the ‘act’ of navigation ‘off of’ your DetailViewController page to my ‘new’ ChosenVendorController page is reissuing a ‘search’.

    2) Your labels placeName, placeFormattedAddress, placeWebsite, are organized a bit different from what I have learned in Objective C so far in that they appear to sort of be ‘inside of’ the interface command in the DetailViewController.h file rather than listed as an @property command. As such, I haven’t figured out the correct syntax/method to refer to them so that I can ‘sync/copy’ their contents into the ‘new labels’ on my ChosenVendorViewController page. It may be that I’m doing it correctly, but the ’500′ error is preventing my command from working. In my “ChosenViewController.m” file I simply added to the “viewDidLoad” routine

    self.vendorNameLabel.text = placeName.text;

    where “vendorNameLabel” is the new label name in my ChosenVendorViewController.m file. Is this the correct method?

    Again, thanks in advance for help to this ‘newbie’!

    Ken

    Reply
    • @Ken – for item number 1. I dont think you want to subclass it at all. I am assuming from the detail view you are selecting something to pass to the vendor view. I would pass either the selected object or an id which the vendor view looks up the proper info.

      for item number 2, I think if you pass an object or an id you dont have to worry about synching/copying the label text to your new labels.

      Hope that helps

      Reply
  18. Hi Joshua,
    My apologies for the wordy ‘comment’. I emailed you the test case in which I simply add a screen and (fail) at passing the text content of the 3 labels on your “Details” screen to 3 new labels on my ‘new screen’ (they show up empty). I’m likely making some kind of ‘noob’ mistake. Feel free to ‘slap me silly’ on my ‘stupidity’ if you have time to take a peek and show me my mistake. Thanks! Ken

    Reply
  19. Joshua,

    Thanks for the ‘fixed’ update to my code. If you think worthwhile to others who may want to learn even more from your ‘googleplaces’ code herein, obviously you are free to add my extended example with your fixes to your post so others can learn from you helping me.

    Thanks again for the education!
    Ken

    Reply
  20. Hi Joshua,

    I downloaded your project and edited the latitude and longitude as 17.4956951, 78.3153106 (place is Chanda Nagar, Hyderabad, Andhra Pradesh, India), in the “searchLocations” only provided “kbar” (also defined and tried with “kSuperMarket” etc) but there is no single result returned while searching for same items in maps.google.co.in returns lots of related businesses.

    Cn you please help me why this is happening?

    Thanks in advance.
    Krishna

    Reply
  21. Hi Josh,
    I’ve almost finished my integration of the mod’d version of your great example code with my first app, but I’m running into the same ARC issue Vuthy Ray did after I refactored your code to make it ARC compatible (got it to build), then I merged with my app I got “Arc Casting” and “ARC Restrictions” flag on the line:

    return GTMCFAutorelease(escaped);
    in the file:
    GTMNSString+URLArguments.m

    I also had a flag in the same section:
    (CFStringRef)self,
    which I “fixed”(?) by modifying to:
    (__bridge CFStringRef)self,

    Not sure even after reading the http://code.google.com/p/google-toolbox-for-mac/wiki/ARC_Compatibility link how to “correctly” fix this.

    Thanks again for all the help to this noob! Hey, I see your company merged/got acquired by another. Hope this was a good thing!
    Ken

    Reply
    • Never mind my earlier request – I chewed on this some more and experimented. I put:
      -fno-objc-arc
      on ‘just’ one file:
      GTMNSString+URLArguments.m
      in my integration of your mod’d file and my app and the red flag went away. There are still some issues, but I want to dig through them some more first and see if I can figure this out. Thanks!

      Reply
  22. Dear,

    I’m trying to use your classes in my app. I copied google places,GTM,Json folders. added necessary frameworks. However, I’m having many errors. mostly parse issue regarding CLLocationCordinate2D in googlePlacesObject and Property ‘latitude’ not found on object of type ‘__strong id’ in googlePlaceConnection.

    Please help.

    Reply
  23. Woah! I’m really loving the template/theme of this site.
    It’s simple, yet effective. A lot of times it’s hard to get that “perfect balance” between superb usability and visual appeal.
    I must say that you’ve done a very good job with this.
    In addition, the blog loads very quick for me on Firefox.
    Exceptional Blog!

    Reply

Leave a Comment.