In this document:
The Facebook SDK for iOS provides prebuilt UI components, including the FBPlacePickerViewController
class that can be used to pick a nearby place.
You can add the place picker programmatically or graphically.
You can create a place picker with the following code in your view controller class:
// Initialize the place picker
FBPlacePickerViewController *placePickerController = [[FBPlacePickerViewController alloc] init];
// Set the place picker title
placePickerController.title = @"Pick Place";
// Hard code current location to Menlo Park, CA
placePickerController.locationCoordinate = CLLocationCoordinate2DMake(37.453827, -122.182187);
// Configure the additional search parameters
placePickerController.radiusInMeters = 1000;
placePickerController.resultsLimit = 50;
placePickerController.searchText = @"restaurant";
// TODO: Set up the place picker delegate to handle
// picker callbacks, ex: Done/Cancel button
// Load the place data
[placePickerController loadData];
// Show the place picker modally
[placePickerController presentModallyFromViewController:self animated:YES handler:nil];
This code initializes the place picker, sets the search parameters, triggers the data fetch and then presents the place picker modally. You can also display the place picker by pushing it onto a UINavigationController
, like this:
...
[self.navigationController pushViewController:placePickerController
animated:YES];
You can add the place picker graphically using the iOS Interface Builder. Do this by using a nib or a storyboard.
Nib setup
To add the place picker through a nib file, create a new class that is a subclass of FBPlacePickerViewController
. When creating the class, select the ''With XIB for user interface'' option:
Next, open your new implementation class and add code to configure the place picker when the class is initialized:
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Set the place picker title
self.title = @"Pick Place";
// Hard code current location to Menlo Park, CA
self.locationCoordinate = CLLocationCoordinate2DMake(37.453827, -122.182187);
// Configure the additional search parameters
self.radiusInMeters = 1000;
self.resultsLimit = 50;
self.searchText = @"restaurant";
}
return self;
}
Then, add code to load the place picker when the view is loaded:
- (void)viewDidLoad
{
[super viewDidLoad];
// Load the place picker data
[self loadData];
}
You can then display your place picker from another view controller by presenting it modally or pushing it onto a UINavigationController
.
Modally:
PPViewController *placeickerController =
[[PPViewController alloc] initWithNibName:@"PPViewController" bundle:nil];
[placeickerController presentModallyFromViewController:self
animated:YES
handler:nil];
Pushing onto a UINavigationController
:
PPViewController *placeickerController =
[[PPViewController alloc] initWithNibName:@"PPViewController" bundle:nil];
[self.navigationController pushViewController:placeickerController
animated:YES];
Creating the place picker through a nib file lets you play with the layout of the picker. For example, let's say you don't want the nearby place list to take over the whole screen, like this:
You accomplish this by making the following changes to your nib:
Table View
object to the layout.tableView
outlet and connect it to your newly created table view.Label
object to the layout and set the text to ''Nearby Places''After your changes, your layout should look something like this:
Storyboard setup
You can make changes to a view controller you've set up inside a storyboard scene. To add the place picker UI control:
View
object in your layout.FBPlacePickerViewController
After your changes, your layout should look like this:
After setting up your layout, add code to configure the place picker. The following code shows how you can do this assuming you've defined a segue named ''SegueToPlacePicker'' for the transition to the place picker:
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:@"SegueToPlacePicker"]) {
// For storyboard, get the destination view controller which
// is the place picker view controller
FBPlacePickerViewController *placePickerController =
(FBPlacePickerViewController *) segue.destinationViewController;
// Confgiure the place picker fetch info using
// a cache descriptor
CLLocationCoordinate2D coordinates =
CLLocationCoordinate2DMake(37.453827, -122.182187);
FBCacheDescriptor *placeCacheDescriptor =
[FBPlacePickerViewController
cacheDescriptorWithLocationCoordinate:coordinates
radiusInMeters:1000
searchText:@"restaurant"
resultsLimit:50
fieldsForRequest:nil];
[placePickerController configureUsingCachedDescriptor:placeCacheDescriptor];
// TODO: Set up the place picker delegate to handle
// picker callbacks, ex: Done/Cancel button
// Load the nearby place data
[placePickerController loadData];
}
}
You should then make the following change to the code that's invoked when your app launches. The changes make sure that the FBPlacePickerViewController
class is loaded before the view is shown:
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
[FBPlacePickerViewController class];
...
return YES;
}
Note: If you've added the -ObjC
flag to your linker options, then you don't have to add this code. Adding that flag causes the linker to load all objects in the Facebook SDK including the FBPlacePickerViewController
class.
There are various events your app may need to handle when you use the place picker.
During data fetch:
When the picker is displayed:
All these events can be handled by defining a class that conforms to the FBPlacePickerDelegate
protocol and implementing the methods you're interested in.
First, add the protocol to the class you wish to handle the delegate callbacks:
@interface ViewController() <FBPlacePickerDelegate>
...
@end
Next, set up the delegate when configuring the place picker.
If you set up your place picker using a nib, you can set the delegate in the view controller's initialization method:
- (id)initWithNibName:(NSString *)nibNameOrNil
bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Set up the delegate
self.delegate = self;
// Set the place picker title
self.title = @"Pick Place";
...
}
return self;
}
If you set up your place picker using a storyboard or programmatically, set the delegate before loading the picker data:
...
// Set the place picker delegate
placePickerController.delegate = self;
// Load the place data
[placePickerController loadData];
...
Once the delegate is set up, implement the desired delegate methods. Example implementations are shown below:
/*
* Event: Error during data fetch
*/
- (void)placePickerViewController:(FBPlacePickerViewController *)placePicker
handleError:(NSError *)error
{
NSLog(@"Error during data fetch.");
}
/*
* Event: Data loaded
*/
- (void)placePickerViewControllerSelectionDidChange:(FBPlacePickerViewController *)placePicker
{
NSLog(@"Place data loaded.");
}
/*
* Event: Decide whether to display a place
*/
- (BOOL)placePickerViewController:(FBPlacePickerViewController *)placePicker
shouldIncludePlace:(id <FBGraphPlace>)place
{
// Filtering example: only show places that have
// "cafe" in their names.
NSRange result = [place.name rangeOfString:@"cafe"
options:NSCaseInsensitiveSearch];
if (result.location != NSNotFound) {
return YES;
} else {
return NO;
}
}
/*
* Event: Selection changed
*/
- (void)placePickerViewControllerDataDidChange:(FBPlacePickerViewController *)placePicker
{
NSLog(@"Current place selected: %@", placePicker.selection);
}
/*
* Event: Done button clicked
*/
- (void)facebookViewControllerDoneWasPressed:(id)sender {
FBPlacePickerViewController *placePickerController =
(FBPlacePickerViewController*)sender;
NSLog(@"Selected place: %@", placePickerController.selection);
// Dismiss the picker
[[sender presentingViewController] dismissModalViewControllerAnimated:YES];
}
/*
* Event: Cancel button clicked
*/
- (void)facebookViewControllerCancelWasPressed:(id)sender {
NSLog(@"Canceled");
// Dismiss the picker
[[sender presentingViewController] dismissModalViewControllerAnimated:YES];
}
The button click events can also be handled if you display the place picker using the following method:
presentModallyFromViewController:animated:handler:
The block you provide to the handler
parameter is called when a person taps the done or cancel buttons, letting you respond to those events. The code below shows an example of using the block:
[placePickerController presentModallyFromViewController:self
animated:YES
handler:
^(FBViewController *sender, BOOL donePressed) {
if(donePressed) {
NSLog(@"Selected place: %@", placePickerController.selection);
}
}];
The default place picker is displayed in the following way:
You can customize these default display features by configuring the relevant properties of FBPlacePickerViewController
:
...
// Hide the place profile pictures
placePickerController.itemPicturesEnabled = NO;
// Load the place data
[placePickerController loadData];
// Hide the done button
placePickerController.doneButton = nil;
// Hide the cancel button
placePickerController.cancelButton = nil;
...
The place picker data is fetched with the following default parameters:
You can customize these default fetch parameters by configuring the relevant properties of FBPlacePickerViewController
directly or by setting these up in a FBCacheDescriptor
for the place picker.
Here's how you can set this up directly through the FBPlacePickerViewController
properties:
...
// Configure the search parameters, look for
// "coffee" places within 500 meters and return
// a maximum of 10 results.
placePickerController.radiusInMeters = 500;
placePickerController.resultsLimit = 10;
placePickerController.searchText = @"coffee";
...
Here's how you can set this up through a FBCacheDescriptor
:
...
// Configure the search parameters, look for
// "coffee" places within 500 meters and return
// a maximum of 10 results.
FBCacheDescriptor *placeCacheDescriptor =
[FBPlacePickerViewController
cacheDescriptorWithLocationCoordinate:coordinates
radiusInMeters:500
searchText:@"coffee"
resultsLimit:10
fieldsForRequest:nil];
[placePickerController configureUsingCachedDescriptor:placeCacheDescriptor];
...
If you need further customizations such as changing the place picker colors or adding more place info to the display, consider building your own picker.
By default, nearby place data is fetched from the server when the loadData
method is called on an FBPlacePickerViewController
instance. While data is being fetched, any previously cached data is used is initially displayed in the picker. The fresh copy is then displayed once it is available.
You can pre-fetch and cache place data before you need to display it. You do this by making use of a FBCacheDescriptor
object that represents the place data you wish to fetch. Once you've created the cache descriptor object you can call the prefetchAndCacheForSession:
method on the object to fetch and cache the place data. The example below shows how to do this in a scenario where you're using CLLocationManager
to get location updates:
- (void)locationManager:(CLLocationManager *)manager
didUpdateToLocation:(CLLocation *)newLocation
fromLocation:(CLLocation *)oldLocation {
if (!oldLocation ||
(oldLocation.coordinate.latitude != newLocation.coordinate.latitude &&
oldLocation.coordinate.longitude != newLocation.coordinate.longitude &&
newLocation.horizontalAccuracy <= 100.0)) {
// Create a cache descriptor based on the new location
FBCacheDescriptor *cacheDescriptor =
[FBPlacePickerViewController
cacheDescriptorWithLocationCoordinate:newLocation.coordinate
radiusInMeters:0
searchText:nil
resultsLimit:0
fieldsForRequest:nil];
// Pre-fetch and cache the place data
[cacheDescriptor prefetchAndCacheForSession:FBSession.activeSession];
}
}
The example above fetches and caches place data when you have updated coordinates from the location manager. It also uses the default search parameters. By default, the following place data is returned in the results: id
, name
, location
, category
, picture
and were_here_count
. You can pre-fetch additional info by setting the fieldsForRequest
parameter in the cacheDescriptorWithLocationCoordinate:radiusInMeters:searchText:resultsLimit:fieldsForRequest:
class method. The example below sets up a fetch for description
and likes
data as well:
// Set up the additional fields needed
NSSet *extraFieldsForPlaceRequest = [NSSet setWithObjects:@"description", @"likes", nil];
// Create a cache descriptor and include the additional fields needed
FBCacheDescriptor *cacheDescriptor =
[FBPlacePickerViewController cacheDescriptorWithLocationCoordinate:newLocation.coordinate
radiusInMeters:0
searchText:nil
resultsLimit:0
fieldsForRequest:extraFieldsForPlaceRequest];
// Pre-fetch and cache the place data
[cacheDescriptor prefetchAndCacheForSession:FBSession.activeSession];
For more information about adding place picker to your iOS apps, see the following.
Find these in the download folder for the Facebook SDK for iOS.
FBPlacePickerViewController
.FBPlacePickerViewController
.FBPlacePickerViewController
.