Working with Facebook Graph API for iOS Apps
Working with social networks inside a mobile app is very common nowadays. The recent versions of iOS have integrated to their SDK the capability to integrate social frameworks like Twitter, Facebook and the latest versions Vimeo.
In this post I’ll show you how to compose a post and how to show your friends list inside your app. There are many things that could be done with the Facebook framework. So first, let's define what is the Facebook graph API.
Facebook Graph API
The Graph API is the principal way to retrieve, post or delete data from the Facebook's social graph. It's a low-level HTTP-based API that is used to query data, post new stories, and upload photos and many other things that can be retrieved in their developers page.
Starting a new project
For this blog I'll build a simple application with a table view that will show us two options. One will allow us to post a new message in our Facebook wall, and the other one will retrieve our list of friends in a different tableview.
The first step is to create a new xcode project with a Single View Application Template. The name of the Application will be "FacebookGraphDemo" with a class prefixed named "FacebookGraph". Select iPhone as device family. Click next and create the project.
Now that we're inside the project lets create the interface that we'll use. Take a look at the sidebar that is at the left of your screen and click on the file that is named "Main. storyboard".
First, we'll drag a UIButton from the elements that are shown in the right-side bar at the bottom. This button will be inside the Facebook Graph View Controller View that you see in the storyboard. Change the title of the button to "Facebook". Once you do this, add another element from the right-side bar named Table View Controller beside the controller that you already have. The next step is to create the view controller file that will get the methods to handle our view that we just added. Click on File>New File. Create an Objective-c file with the name of FacebookGraphTableViewController from the subclass "UITableViewController". To connect your storyboard view, with this file go back to the storyboard and select the table view controller that we added and select the identity inspector in the right-side bar. Select the Class picker under the Custom class section and select the "FacebookGraphTableViewController" option that appears there.
The next step is to make some static cells in our table view. Select the table view inside our controller in the storyboard and select the Attribute inspector in the right side bar of the screen. Under the Table View Section change the content type to Static Cells. You should have something like this:
Click on the first cell, change the style to basic and rename the title of the cell to "Compose". Repeat the same steps on the second cell and rename it to "Get my friends". Now that we have our two view controllers we will connect them.
In order to connect to our table view controllers, we need to connect the Facebook button with the tableView by holding the ctrl key and clicking at the same time the button. Hold the click plus the ctrl button and drag the line that appears into the table view controller. It will appear a popover with some options for Action Segue; select the "Push" option
At last, to finish the first part of the Interface Builder click on the first controller and then select in the top finder bar the option Editor > Embed In > Navigation controller. This will let us make the navigation between the two screens. At this point, if you run your application you will be able to change between screens. You'll notice that the tableview will be in blank. We'll get to it in the next step.
In order to display the two cells in our tableview and add them functionality we have to edit our FacebookGraphTableViewControlle.m file. Add the following code inside the file:
<span style="font-size: 13px;"><em>#import "FacebookGraphTableViewController.h"</em></span> <span style="font-size: 13px;"><em>#import <Social/Social.h></em></span> <span style="font-size: 13px;"><em>#import <MessageUI/MessageUI.h></em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>@interface FacebookGraphTableViewController ()</em></span> <span style="font-size: 13px;"><em>@end</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>typedef NS_ENUM(NSInteger, FacebookOptions) {</em></span> <span style="font-size: 13px;"><em> //Options that will be available once the user clicks a row</em></span> <span style="font-size: 13px;"><em> kFacebookGraphCompose = 0,</em></span> <span style="font-size: 13px;"><em> kFacebookGraphFriendList</em></span> <span style="font-size: 13px;"><em>};</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>@implementation FacebookGraphTableViewController</em></span> <span style="font-size: 13px;"><em>- (id)initWithStyle:(UITableViewStyle)style</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> self = [super initWithStyle:style];</em></span> <span style="font-size: 13px;"><em> if (self) {</em></span> <span style="font-size: 13px;"><em> // Custom initialization</em></span> <span style="font-size: 13px;"><em> }</em></span> <span style="font-size: 13px;"><em> return self;</em></span> <span style="font-size: 13px;"><em>}</em></span><span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>- (void)viewDidLoad</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> [super viewDidLoad];</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>- (void)didReceiveMemoryWarning</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> [super didReceiveMemoryWarning];</em></span> <span style="font-size: 13px;"><em> // Dispose of any resources that can be recreated.</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>#pragma mark - Table view data source</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> // Return the number of sections.</em></span> <span style="font-size: 13px;"><em> return 1;</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> // Return the number of rows in the section. In this case we only have two options</em></span> <span style="font-size: 13px;"><em> return 2;</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>#pragma mark UITableViewDelegate</em></span> <span style="font-size: 13px;"><em>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {</em></span> <span style="font-size: 13px;"><em> //Once the user selects an option we'll check the enumeration that we did before</em></span> <span style="font-size: 13px;"><em> switch ((FacebookOptions)[indexPath row]) {</em></span> <span style="font-size: 13px;"><em> case kFacebookGraphCompose:</em></span> <span style="font-size: 13px;"><em> //call the post to facebook method declared below</em></span> <span style="font-size: 13px;"><em> [self postToFacebook];</em></span> <span style="font-size: 13px;"><em> break;</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em> case kFacebookGraphFriendList:</em></span> <span style="font-size: 13px;"><em> //Space for the list of friends show </em></span> <span style="font-size: 13px;"><em> break;</em></span> <span style="font-size: 13px;"><em> default:</em></span> <span style="font-size: 13px;"><em> break;</em></span> <span style="font-size: 13px;"><em> }</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>-(void)postToFacebook</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> //Check if the current device is available to show the Facebook Composer</em></span> <span style="font-size: 13px;"><em> if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {</em></span> <span style="font-size: 13px;"><em> SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];</em></span> <span style="font-size: 13px;"><em> //Set an initial text in the composer</em></span> <span style="font-size: 13px;"><em> [controller setInitialText:@"Hello Facebook!"];</em></span> <span style="font-size: 13px;"><em> //Present the composer in the current controller</em></span> <span style="font-size: 13px;"><em> [self presentViewController:controller animated:YES completion:nil];</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em> }else{</em></span> <span style="font-size: 13px;"><em> //If the Composer is not available display an alert so the user can go to the device settings manually</em></span> <span style="font-size: 13px;"><em> UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oops"</em></span> <span style="font-size: 13px;"><em> message:@"You can't send this right now, make sure your device has an internet connection and you have at least one Facebook account setup in Settings"</em></span> <span style="font-size: 13px;"><em> delegate:nil</em></span> <span style="font-size: 13px;"><em> cancelButtonTitle:@"OK"</em></span> <span style="font-size: 13px;"><em> otherButtonTitles:nil];</em></span> <span style="font-size: 13px;"><em> [alert show];</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em> }</em></span> <span style="font-size: 13px;"><em>}</em></span><span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>// In a storyboard-based application, you will often want to do a little preparation before navigation</em></span> <span style="font-size: 13px;"><em>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> // This space will be used for the second row method</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>@end</em></span> |
At this point we're able to run our app and see the main table with the two options. The first one will be available to compose a new Facebook message if the device has a Facebook account subscribed.
For our next part, we're going to make the function so the app can connect with the graph API and retrieve a list of the user friends in a table view. Before continuing with this we'll need to access to the Facebook developer site in order to set a new application that could connect with our iOS application.
The first step is to make an application in Facebook’s developer site, go to https://developers.facebook.com/ and look for the applications section. You'll be asked to sign in to Facebook. Once you sign in create a new application and name it Graph App Demo. It should look something like this:
For the next step go to the configurations and add a new platform that will be available with our app. Click on the iOS option, you'll be returned to the configuration window. In the field that says "bundle id" set the same bundle id that is set on your xcode app. Save the changes and copy the Application ID that appears at the top, we'll use it later in our application.
After this app registration, go back to xcode and add a new table view controller to the storyboard. Set it up with one cell. Inside of the cell add an image view, an activity indicator, and a label. Set to the imageview a Tag number of 100 in the attribute inspector. Do the same with the activity indicator (Tag: 102) and with the label (Tag: 101). This will help us to identify the views later in our “.m” file. Click on the table view cell and change the Identifier under the Table View Cell section to friendCell. At this point you should have something like this:
After configuring this, it will be necessary to create another Objective-C file. We'll name this file FBFriendsViewController. Be sure to create it as a subclass of UITableViewController. Go back to the storyboard and associate the table that we created with the Objective-C file as we did it before.
Open the FacebookGraphTableViewController.h file and add the missing lines that you see below.
<span style="font-size: 13px;"><em>//FacebookGraphTableViewController.h</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>#import <UIKit/UIKit.h></em></span>
<span style="font-size: 13px;"><em>#import <Accounts/Accounts.h></em></span>
<span style="font-size: 13px;"><em>#import <Social/Social.h></em></span>
<span style="font-size: 13px;"><em>#import <A</em><em>ddressBook/AddressBook.h></em></span>
<span style="font-size: 13px;"><em>#import "FBFriendsTableViewController.h"</em></span>
<span style="font-size: 13px;"><em>//Declare the block that will execute after receiving success from the method</em></span>
<span style="font-size: 13px;"><em>typedef void (^FriendsCallbackSuccess)(NSArray *successArray);</em></span>
<span style="font-size: 13px;"><em>//Declre the block that will execute after receiving error from the method</em></span>
<span style="font-size: 13px;"><em>typedef void (^FriendsCallbackError)(NSString *errorString);</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>@interface FacebookGraphTableViewController : UITableViewController</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em>//Create an instance for the Controller with our friends list</em></span>
<span style="font-size: 13px;"><em> FBFriendsTableViewController *fbFriendsController;</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>@property (strong,nonatomic)FriendsCallbackSuccess success;</em></span>
<span style="font-size: 13px;"><em>@property (strong,nonatomic)FriendsCallbackError error;</em></span>
<span style="font-size: 13px;"><em>//Create an array that will be used for storing the dictionary of friends from facebook</em></span>
<span style="font-size: 13px;"><em>@property (strong, nonatomic)NSArray *theFriendsArray;</em></span>
<span style="font-size: 13px;"><em>@end</em> </span>
<span style="font-size: 13px;">After this we'll add the new methods that will be on the .m file, add only the ones that are missing :</span>
<span style="font-size: 13px;"><em>//FacebookGraphTableViewController.m</em></span>
<span style="font-size: 13px;"><em>#import "FacebookGraphTableViewController.h"</em></span>
<span style="font-size: 13px;"><em>#import <Social/Social.h></em></span>
<span style="font-size: 13px;"><em>#import <MessageUI/MessageUI.h></em></span>
<span style="font-size: 13px;"><em>#import "FBFriendsTableViewController.h"</em></span>
<span style="font-size: 13px;"><em>@interface FacebookGraphTableViewController ()</em></span>
<span style="font-size: 13px;"><em>@end</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>typedef NS_ENUM(NSInteger, FacebookOptions) {</em></span>
<span style="font-size: 13px;"><em> //Options that will be available once the user clicks a row</em></span>
<span style="font-size: 13px;"><em> kFacebookGraphCompose = 0,</em></span>
<span style="font-size: 13px;"><em> kFacebookGraphFriendList</em></span>
<span style="font-size: 13px;"><em>};</em></span>
<span style="font-size: 13px;"><em>@implementation FacebookGraphTableViewController</em></span>
<span style="font-size: 13px;"><em>- (id)initWithStyle:(UITableViewStyle)style</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> self = [super initWithStyle:style];</em></span>
<span style="font-size: 13px;"><em> if (self) {</em></span>
<span style="font-size: 13px;"><em> // Custom initialization</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em> return self;</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>- (void)viewDidLoad</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> [super viewDidLoad];</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>- (void)didReceiveMemoryWarning</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> [super didReceiveMemoryWarning];</em></span>
<span style="font-size: 13px;"><em> // Dispose of any resources that can be recreated.</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>#pragma mark - Table view data source</em></span>
<span style="font-size: 13px;"><em>- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> // Return the number of sections.</em></span>
<span style="font-size: 13px;"><em> return 1;</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> // Return the number of rows in the section. In this case we only have two options</em></span>
<span style="font-size: 13px;"><em> return 2;</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>#pragma mark UITableViewDelegate</em></span>
<span style="font-size: 13px;"><em>- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {</em></span>
<span style="font-size: 13px;"><em> //Once the user selects an option we'll check the enumeration that we did before</em></span>
<span style="font-size: 13px;"><em> switch ((FacebookOptions)[indexPath row]) {</em></span>
<span style="font-size: 13px;"><em> case kFacebookGraphCompose:</em></span>
<span style="font-size: 13px;"><em> //call the post to facebook method declared below</em></span>
<span style="font-size: 13px;"><em> [self postToFacebook];</em></span>
<span style="font-size: 13px;"><em> break;</em></span>
<span style="font-size: 13px;"><em> case kFacebookGraphFriendList:</em></span>
<span style="font-size: 13px;"><em> [self getFriendsArray];</em></span>
<span style="font-size: 13px;"><em> break;</em></span>
<span style="font-size: 13px;"><em> default:</em></span>
<span style="font-size: 13px;"><em> break;</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>-(void)postToFacebook</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> //Check if the current device is available to show the Facebook Composer</em></span>
<span style="font-size: 13px;"><em> if ([SLComposeViewController isAvailableForServiceType:SLServiceTypeFacebook]) {</em></span>
<span style="font-size: 13px;"><em> SLComposeViewController *controller = [SLComposeViewController composeViewControllerForServiceType:SLServiceTypeFacebook];</em></span>
<span style="font-size: 13px;"><em> //Set an initial text in the composer</em></span>
<span style="font-size: 13px;"><em> [controller setInitialText:@"Hello Facebook!"];</em></span>
<span style="font-size: 13px;"><em> //Present the composer in the current controller</em></span>
<span style="font-size: 13px;"><em> [self presentViewController:controller animated:YES completion:nil];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> }else{</em></span>
<span style="font-size: 13px;"><em> //If the Composer is not available display an alert so the user can go to the device settings manually</em></span>
<span style="font-size: 13px;"><em> UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Oops"</em></span>
<span style="font-size: 13px;"><em> message:@"You can't send this right now, make sure your device has an internet connection and you have at least one Facebook account setup in Settings"</em></span>
<span style="font-size: 13px;"><em> delegate:nil</em></span>
<span style="font-size: 13px;"><em> cancelButtonTitle:@"OK"</em></span>
<span style="font-size: 13px;"><em> otherButtonTitles:nil];</em></span>
<span style="font-size: 13px;"><em> [alert show];</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>-(void)getFriendsArray</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em>//Create a shadow view to create a user feedback loading animator</em></span>
<span style="font-size: 13px;"><em> UIView *shadowView = [[UIView alloc]initWithFrame:self.navigationController.view.frame];</em></span>
<span style="font-size: 13px;"><em> [self.navigationController.view addSubview:shadowView];</em></span>
<span style="font-size: 13px;"><em> [shadowView setBackgroundColor:[[UIColor blackColor]colorWithAlphaComponent:0.6]];</em></span>
<span style="font-size: 13px;"><em>//Add and activity indicator </em></span>
<span style="font-size: 13px;"><em>UIActivityIndicatorView *activityIndicator = [[UIActivityIndicatorView alloc]initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];</em></span>
<span style="font-size: 13px;"><em> [activityIndicator setFrame:CGRectMake(self.view.center.x - 25, self.view.center.y - 25, 50, 50)];</em></span>
<span style="font-size: 13px;"><em> UILabel *loadingLabel = [[UILabel alloc]initWithFrame:CGRectMake(self.view.center.x -25, self.view.center.y + 25, 100, 30)];</em></span>
<span style="font-size: 13px;"><em> [loadingLabel setText:@"Loading..."];</em></span>
<span style="font-size: 13px;"><em> [loadingLabel setTextColor:[UIColor whiteColor]];</em></span>
<span style="font-size: 13px;"><em>//Star animating while the method is executed </em></span>
<span style="font-size: 13px;"><em> [activityIndicator startAnimating];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> [shadowView addSubview:activityIndicator];</em></span>
<span style="font-size: 13px;"><em> [shadowView addSubview:loadingLabel];</em></span>
<span style="font-size: 13px;"><em> </em></span><span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>//Call the method to get facebook friends declared below</em></span>
<span style="font-size: 13px;"><em> [self getFacebookFriends:^(NSArray *successArray) {</em></span>
<span style="font-size: 13px;"><em> //Receive the array that is generated after success</em></span>
<span style="font-size: 13px;"><em> self.theFriendsArray = successArray;</em></span>
<span style="font-size: 13px;"><em> dispatch_async(dispatch_get_main_queue(), ^{</em></span>
<span style="font-size: 13px;"><em> //Execute the segue on the main queue so the UI doesn't get affected</em></span>
<span style="font-size: 13px;"><em> [self performSegueWithIdentifier:@"showFriendsSegue" sender:self];</em></span>
<span style="font-size: 13px;"><em> //Once the method is completed stop the animation of the activity indicator and remove the shadow view. </em></span>
<span style="font-size: 13px;"><em> [activityIndicator stopAnimating];</em></span>
<span style="font-size: 13px;"><em> [shadowView removeFromSuperview];</em></span>
<span style="font-size: 13px;"><em> });</em></span>
<span style="font-size: 13px;"><em> } error:^(NSString *errorString) {</em></span>
<span style="font-size: 13px;"><em> }];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>-(void)getFacebookFriends: (FriendsCallbackSuccess)success error:(FriendsCallbackError)inError</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> ACAccountStore *store = [[ACAccountStore alloc]init];</em></span>
<span style="font-size: 13px;"><em> //Specify the account that we're going to use, in this case Facebook</em></span>
<span style="font-size: 13px;"><em> ACAccountType *facebookAccount = [store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];</em></span>
<span style="font-size: 13px;"><em> //Give the app ID (the one we copied before in our FB application at developer's site), permission keys and the audience that can see what we do (in case we do a POST)</em></span>
<span style="font-size: 13px;"><em> NSDictionary *FacebookOptions = @{ACFacebookAppIdKey: @"1476105562622265", ACFacebookPermissionsKey: @[@"email",@"read_friendlists"],ACFacebookAudienceKey:ACFacebookAudienceFriends};</em></span>
<span style="font-size: 13px;"><em> //Request access to the account with the options that we established before</em></span>
<span style="font-size: 13px;"><em> [store requestAccessToAccountsWithType:facebookAccount options:FacebookOptions completion:^(BOOL granted, NSError *error) {</em></span>
<span style="font-size: 13px;"><em> //Check if everything inside our app that we created at facebook developer is valid</em></span>
<span style="font-size: 13px;"><em> if (granted)</em></span>
<span style="font-size: 13px;"><em> {</em></span>
<span style="font-size: 13px;"><em> NSArray *accounts = [store accountsWithAccountType:facebookAccount];</em></span>
<span style="font-size: 13px;"><em> //Get the accounts linked to facebook in the device</em></span>
<span style="font-size: 13px;"><em> if ([accounts count]>0) {</em></span>
<span style="font-size: 13px;"><em> ACAccount *facebookAccount = [accounts lastObject];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> //Set the parameters that we require for our friend list</em></span>
<span style="font-size: 13px;"><em> NSDictionary *param=[NSDictionary dictionaryWithObjectsAndKeys:@"picture.width(1000).height(1000),name,link",@"fields", nil];</em></span>
<span style="font-size: 13px;"><em> //Generate the facebook request to the graph api, we'll call the taggle friends api, that will give us the details from our list of friends</em></span>
<span style="font-size: 13px;"><em> SLRequest *facebookRequest = [SLRequest requestForServiceType:SLServiceTypeFacebook requestMethod:SLRequestMethodGET URL:[NSURL URLWithString:@"<a href="https://graph.facebook.com/v2.0/me/taggable_friends">https://graph.facebook.com/v2.0/me/taggable_friends</a></em><em>"] parameters:param];</em></span>
<span style="font-size: 13px;"><em> //Set the parameters and request to the FB account</em></span>
<span style="font-size: 13px;"><em> [facebookRequest setAccount:facebookAccount];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> [facebookRequest performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {</em></span>
<span style="font-size: 13px;"><em> // Read the returned response</em></span>
<span style="font-size: 13px;"><em> if(!error){</em></span>
<span style="font-size: 13px;"><em> self.success = success;</em></span>
<span style="font-size: 13px;"><em> //Read the response in a JSON format</em></span>
<span style="font-size: 13px;"><em> id json =[NSJSONSerialization JSONObjectWithData:responseData options:kNilOptions error:&error];</em></span>
<span style="font-size: 13px;"><em> NSLog(@"Dictionary contains data: %@", json );</em></span>
<span style="font-size: 13px;"><em> if([json objectForKey:@"error"]!=nil)</em></span>
<span style="font-size: 13px;"><em> {</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em> //Get the data inside of the json in an array</em></span>
<span style="font-size: 13px;"><em> NSArray *allFriends = [json objectForKey:@"data"];</em></span>
<span style="font-size: 13px;"><em> //Prepare the array that we will send</em></span>
<span style="font-size: 13px;"><em> NSMutableArray *friendsArray = [[NSMutableArray alloc]init];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> for (NSDictionary *userInfo in allFriends)</em></span>
<span style="font-size: 13px;"><em> {</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> NSString *userName = [userInfo objectForKey:@"name"];</em></span>
<span style="font-size: 13px;"><em> NSDictionary *pictureData = [[userInfo objectForKey:@"picture"] objectForKey:@"data"];</em></span>
<span style="font-size: 13px;"><em> NSString *imageUrl = [pictureData objectForKey:@"url"];</em></span>
<span style="font-size: 13px;"><em> //Save all the user information in a dictionary that will contain the basic info that we need</em></span>
<span style="font-size: 13px;"><em> NSDictionary *friendCollection = [[NSDictionary alloc]initWithObjects:@[userName, imageUrl] forKeys:@[@"username", @"picURL"]];</em></span>
<span style="font-size: 13px;"><em> //Store each dictionary inside the array that we created</em></span>
<span style="font-size: 13px;"><em> [friendsArray addObject:friendCollection];</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em> //Send the array that we created to a success call</em></span>
<span style="font-size: 13px;"><em> success(friendsArray);</em></span><span style="font-size: 13px;"><em> </em></span><span style="font-size: 13px;"><em> </em></span><span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> NSLog(@"URL %@", urlResponse);</em></span>
<span style="font-size: 13px;"><em> NSLog(@"%@", [[NSString alloc]initWithData:responseData encoding:NSUTF8StringEncoding]);</em></span>
<span style="font-size: 13px;"><em> }];</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em> }else{</em></span>
<span style="font-size: 13px;"><em> //If there was an error, show in console the code number</em></span>
<span style="font-size: 13px;"><em> NSLog(@"ERROR: %@", error);</em></span>
<span style="font-size: 13px;"><em> self.error = inError;</em></span>
<span style="font-size: 13px;"><em> }</em></span><span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em> }];</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em> </em></span>
<span style="font-size: 13px;"><em>- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender</em></span>
<span style="font-size: 13px;"><em>{</em></span>
<span style="font-size: 13px;"><em> if ([[segue identifier] isEqualToString:@"showFriendsSegue"]) {</em></span>
<span style="font-size: 13px;"><em>//Get the controller for facebook friends table</em></span>
<span style="font-size: 13px;"><em> fbFriendsController = [[FBFriendsTableViewController alloc]init];</em></span>
<span style="font-size: 13px;"><em> fbFriendsController = [segue destinationViewController];</em></span>
<span style="font-size: 13px;"><em> //Send the array that we received in the graph api call success to the table where we'll store our friends</em></span>
<span style="font-size: 13px;"><em> [fbFriendsController setFriendsArray:self.theFriendsArray];</em></span>
<span style="font-size: 13px;"><em> }</em></span>
<span style="font-size: 13px;"><em>}</em></span>
<span style="font-size: 13px;"><em>@end</em></span>
|
At this point we're almost over with the application. Our main method for the function that we want to execute is the "getFacebookFriends: (FriendsCallbackSuccess) success error:(FriendsCallbackError) error". This method calls the Graph API directly with the SLRequest function. In order to get the data we need to send some permission and some parameters to the request. Once these are set, we'll receive the data and we will convert that data into a JSON. From this JSON we'll get an array containing all the data that we requested in the parameters from each user. After receiving each user as an object inside the array, we will generate a dictionary for each of them and store them in another array. This array will be sent in a success call.
The only missing part for this is how the FBFriendsTableViewController is going to handle this array. For this we'll add the following code in .h and .m files.
<span style="font-size: 13px;"><em>// FBFriendsTableViewController.h</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>#import <UIKit/UIKit.h></em></span><span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>@interface FBFriendsTableViewController : UITableViewController</em></span> <span style="font-size: 13px;"><em>@property(nonatomic, strong)NSArray *friendsArray;</em></span> <span style="font-size: 13px;"><em>@end</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>// FBFriendsTableViewController.m</em></span> <span style="font-size: 13px;"><em>#import "FBFriendsTableViewController.h"</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>@interface FBFriendsTableViewController ()</em></span> <span style="font-size: 13px;"><em>@end</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>@implementation FBFriendsTableViewController</em></span> <span style="font-size: 13px;"><em>- (id)initWithStyle:(UITableViewStyle)style</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> self = [super initWithStyle:style];</em></span> <span style="font-size: 13px;"><em> if (self) {</em></span> <span style="font-size: 13px;"><em> // Custom initialization</em></span> <span style="font-size: 13px;"><em> }</em></span> <span style="font-size: 13px;"><em> return self;</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>- (void)viewDidLoad</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> [super viewDidLoad];</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>- (void)didReceiveMemoryWarning</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> [super didReceiveMemoryWarning];</em></span> <span style="font-size: 13px;"><em> // Dispose of any resources that can be recreated.</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>#pragma mark - Table view data source</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> // Return the number of sections.</em></span> <span style="font-size: 13px;"><em> return 1;</em></span> <span style="font-size: 13px;"><em>}</em></span><span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em>- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> // Return the number of rows in the section.</em></span> <span style="font-size: 13px;"><em> return [self.friendsArray count];</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath</em></span> <span style="font-size: 13px;"><em>{</em></span> <span style="font-size: 13px;"><em> UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"friendCell" forIndexPath:indexPath];</em></span> <span style="font-size: 13px;"><em> //Identify the outlets that we created at the interface builder</em></span> <span style="font-size: 13px;"><em> UIActivityIndicatorView *activityIndicator = (UIActivityIndicatorView *)[cell viewWithTag:102];</em></span> <span style="font-size: 13px;"><em> UILabel *nameLabel = (UILabel *)[cell viewWithTag:101];</em></span> <span style="font-size: 13px;"><em> UIImageView *imageView = (UIImageView *)[cell viewWithTag:100];</em></span> <span style="font-size: 13px;"><em> //Get the dictionary stored for the user at the current index</em></span> <span style="font-size: 13px;"><em> NSDictionary *friendDictionary = [self.friendsArray objectAtIndex:indexPath.row];</em></span> <span style="font-size: 13px;"><em> //Set the name label</em></span> <span style="font-size: 13px;"><em> [nameLabel setText:[friendDictionary objectForKey:@"username"]];</em></span> <span style="font-size: 13px;"><em> //Show the activity indicator so the user gets some feedback</em></span> <span style="font-size: 13px;"><em> [activityIndicator startAnimating];</em></span> <span style="font-size: 13px;"><em> //Create another thread so the UI is not affected when loading the images</em></span> <span style="font-size: 13px;"><em> dispatch_queue_t myQueue = dispatch_queue_create("com.itexico.FBgraph", 0);</em></span> <span style="font-size: 13px;"><em> dispatch_async(myQueue, ^{</em></span> <span style="font-size: 13px;"><em> UIImage *image;</em></span> <span style="font-size: 13px;"><em> //Get the image from the url received</em></span> <span style="font-size: 13px;"><em> NSURL *picUrl = [NSURL URLWithString:[friendDictionary objectForKey:@"picURL"]];</em></span> <span style="font-size: 13px;"><em> image = [UIImage imageWithData:[NSData dataWithContentsOfURL:picUrl]];</em></span> <span style="font-size: 13px;"><em> </em></span> <span style="font-size: 13px;"><em> dispatch_async(dispatch_get_main_queue(), ^{</em></span> <span style="font-size: 13px;"><em> //When the image is received show it in the imageview</em></span> <span style="font-size: 13px;"><em> imageView.image = image;</em></span> <span style="font-size: 13px;"><em> [imageView setContentMode:UIViewContentModeScaleAspectFit];</em></span> <span style="font-size: 13px;"><em> //Hide the activity indicator</em></span> <span style="font-size: 13px;"><em> activityIndicator.hidden = YES;</em></span> <span style="font-size: 13px;"><em> [activityIndicator stopAnimating];</em></span> <span style="font-size: 13px;"><em> [imageView setNeedsLayout];</em></span> <span style="font-size: 13px;"><em> });</em></span> <span style="font-size: 13px;"><em> });</em></span> <span style="font-size: 13px;"><em> return cell;</em></span> <span style="font-size: 13px;"><em>}</em></span> <span style="font-size: 13px;"><em>@end</em></span> |
This part of the code is the visual interface that the user will be able to see with the name of his friends and their pictures. This data was sent previously within an array that we generated in the past table view controller. We fill the table with the dictionary that was created for each user. Our final result should look similar to the screen below.
Further applications of the Graph API methods
There are many methods that could be executed using the graph API. There are POST, GET and DELETE methods that could be called directly from our apps using the right permissions. Many applications like Spotify, Shazam, or games at the app store use this API so you can retrieve your friends, pictures, or other things from your Facebook account. I'll recommend you to visit the developer site to check which other permissions are available and also to debug your API calls with the graph API explorer that could be found in Facebook Developers page. This is a really useful tool to check which API calls are possible and which permissions you need to add.
About the Author
Ernesto S. is a Technology and Communication Engineer. He has been working on iOS mobile app development for 2+ years. Ernesto is a full Native iOS software developer.
Post Your Comment Here