Facebook IOS SDK: store facebook request callback data into global variable - ios

I'm using the new facebook ios sdk. I request for friends data using the new function showed below. However, since it is a function with a block as a parameter I lost these data outside the function. How can I preserve the data (i.e. store in a global variable) so that I can use it in another function?
Thanks in advance.
code:
-(void)requestFriends {
[FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection* connection, id data, NSError *error) {
if(error) {
[self printError:#"Error requesting /me/friends" error:error];
return;
}
NSArray* friends = (NSArray*)[data data];
}];

Just store it on a property, and refresh the UI after that.
// in .h or class extension
#property(nonatomic, strong) NSArray *friends;
-(void)requestFriends {
[FBRequestConnection startForMyFriendsWithCompletionHandler:^(FBRequestConnection* connection, id data, NSError *error) {
if(error) {
[self printError:#"Error requesting /me/friends" error:error];
return;
}
self.friends = (NSArray*)[data data];
}];

Related

How to get Friends list from Facebook iOS sdk

I am using iOS sdk v3.18.1, I want to get all my Facebook friends.I can get the friends count but, data is nil.
Here is my code
[FBRequestConnection startWithGraphPath:#"me/friends" parameters:nil HTTPMethod:#"GET" completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
NSLog(#"result %#",result);
}];
Out put
{
data = (
);
summary = {
"total_count" = 840;
};
}
https://developers.facebook.com/docs/apps/changelog
Since v2.0 you cannot get the full friend list anymore, you only get the friends who authorized your App too.
See my answer in this thread too: how to get a list of all user friends (not only who use the app)?
// declare an array in header file which will hold the list of all friends -
NSMutableArray * m_allFriends;
// alloc and initialize the array only once
m_allFriends = [[NSMutableArray alloc] init];
With FB SDK 3.0 and API Version above 2.0 you need to call below function (graph api with me/friends)to get list of FB Friends which uses the same app.
// get friends which use the app
-(void) getMineFriends
{
[FBRequestConnection startWithGraphPath:#"me/friends"
parameters:nil
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"me/friends result=%#",result);
NSLog(#"me/friends error = %#", error.description);
NSArray *friendList = [result objectForKey:#"data"];
[m_allFriends addObjectsFromArray: friendList];
}];
}
Note : 1) The default limit for the number of friends returned by above query is 25. 2)If the next link comes in result, that means there are some more friends which you will be fetching in next query and so on. 3)Alternatively you can change the limit (reduce the limit, exceed the limit from 25) and pass that in param.
////////////////////////////////////////////////////////////////////////
For non app friends -
// m_invitableFriends - global array which will hold the list of invitable friends
Also to get non app friends you need to use (/me/invitable_friends) as below -
- (void) getAllInvitableFriends
{
NSMutableArray *tempFriendsList = [[NSMutableArray alloc] init];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:#"100", #"limit", nil];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
- (void) getAllInvitableFriendsFromFB:(NSDictionary*)parameters
addInList:(NSMutableArray *)tempFriendsList
{
[FBRequestConnection startWithGraphPath:#"/me/invitable_friends"
parameters:parameters
HTTPMethod:#"GET"
completionHandler:^(
FBRequestConnection *connection,
id result,
NSError *error
) {
NSLog(#"error=%#",error);
NSLog(#"result=%#",result);
NSArray *friendArray = [result objectForKey:#"data"];
[tempFriendsList addObjectsFromArray:friendArray];
NSDictionary *paging = [result objectForKey:#"paging"];
NSString *next = nil;
next = [paging objectForKey:#"next"];
if(next != nil)
{
NSDictionary *cursor = [paging objectForKey:#"cursors"];
NSString *after = [cursor objectForKey:#"after"];
//NSString *before = [cursor objectForKey:#"before"];
NSDictionary *limitParam = [NSDictionary dictionaryWithObjectsAndKeys:
#"100", #"limit", after, #"after"
, nil
];
[self getAllInvitableFriendsFromFB:limitParam addInList:tempFriendsList];
}
else
{
[self replaceGlobalListWithRecentData:tempFriendsList];
}
}];
}
- (void) replaceGlobalListWithRecentData:(NSMutableArray *)tempFriendsList
{
// replace global from received list
[m_invitableFriends removeAllObjects];
[m_invitableFriends addObjectsFromArray:tempFriendsList];
//NSLog(#"friendsList = %d", [m_invitableFriends count]);
[tempFriendsList release];
}
For Inviting non app friend -
you will get invite tokens with the list of friends returned by me/invitable_friends graph api. You can use these invite tokens with FBWebDialogs to send invite to friends as below
- (void) openFacebookFeedDialogForFriend:(NSString *)userInviteTokens {
NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:
userInviteTokens, #"to",
nil, #"object_id",
#"send", #"action_type",
actionLinksStr, #"actions",
nil];
[FBWebDialogs
presentRequestsDialogModallyWithSession:nil
message:#"Hi friend, I am playing game. Come and play this awesome game with me."
title:nil
parameters:params
handler:^(
FBWebDialogResult result,
NSURL *url,
NSError *error)
{
if (error) {
// Error launching the dialog or sending the request.
NSLog(#"Error sending request : %#", error.description);
}
else
{
if (result == FBWebDialogResultDialogNotCompleted)
{
// User clicked the "x" icon
NSLog(#"User canceled request.");
NSLog(#"Friend post dialog not complete, error: %#", error.description);
}
else
{
NSDictionary *resultParams = [g_mainApp->m_appDelegate parseURLParams:[url query]];
if (![resultParams valueForKey:#"request"])
{
// User clicked the Cancel button
NSLog(#"User canceled request.");
}
else
{
NSString *requestID = [resultParams valueForKey:#"request"];
// here you will get the fb id of the friend you invited,
// you can use this id to reward the sender when receiver accepts the request
NSLog(#"Feed post ID: %#", requestID);
NSLog(#"Friend post dialog complete: %#", url);
}
}
}
}];
}
Since, V2.0 of the Graph API, You will only be able to get the list of the friends who are connected with your app. In v2.0 of the Graph API, calling /me/friends returns the person's friends who use the app. Yes it is possible to get the count but accessing the friend list is not possible.
All the release of Facebook SDK after the month of April denies this functionality of getting the whole list of friends.
REFER : SO QUESTION:Facebook graph API returns empty .... FACEBOOK USER GUIDE
This has been confirmed by FACEBOOK.

Can't get permissions for user_birthday and user_hometown in facebook-ios-sdk

I am not able to get the permissions for user_birthday and user_hometown.
I tried it with this code before but it only asks for the public profile and ignores others.
[FBSession openActiveSessionWithReadPermissions:#[#"public_profile",#"user_birthday",#"user_hometown"]
allowLoginUI:YES completionHandler:^(FBSession *session, FBSessionState status, NSError *error) {
if (error) {
NBAppDelegate* appDel = (NBAppDelegate*)`[UIApplication sharedApplication].delegate;
[appDel sessionStateChanged:session state:status error:error];
}
if ([session isOpen]) {
[self loginWithFBToken:session name:sender];
}
}];
Then someone suggested to ask for additional permissions after getting the public profile, so i even tried that to no good.
Here is the code for that
- (void)loadFbDetails
{
NSArray *permissionsNeeded = #[#"user_hometown", #"user_birthday"];
// Request the permissions the user currently has
[FBRequestConnection startWithGraphPath:#"/me/permissions"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
// These are the current permissions the user has:
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
// We will store here the missing permissions that we will have to request
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
// Check if all the permissions we need are present in the user's current permissions
// If they are not present add them to the permissions to be requested
for (NSString *permission in permissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
// If we have permissions to request
if ([requestPermissions count] > 0){
// Ask for the missing permissions
[FBSession.activeSession
requestNewReadPermissions:requestPermissions
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
// Permission granted
NSLog(#"new permissions %#", [FBSession.activeSession permissions]);
// We can request the user information
[self makeRequestForUserData];
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
} else {
// Permissions are present
// We can request the user information
[self makeRequestForUserData];
}
} else {
// An error occurred, we need to handle the error
// See: https://developers.facebook.com/docs/ios/errors
}
}];
}
-(void)makeRequestForUserData
{
[FBRequestConnection startWithGraphPath:#"me?fields=birthday,hometown"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error) {
// Sucess! Include your code to handle the results here
NSLog(#"user events: %#", result);
} else {
NSLog(#"error: %#" , error);
}
}];
}
All it does is recursively go between my ios app and the fb native app, returning only with the public_profile in the permissions array.
Looks like i am missing something?
It should work if you're using an admin user of the app. Once you want to use the extended permissions with other users, you have to get your app reviewed by Facebook first.
See my answer here: facebook extended permission
Facebook does not allow apps to access that information by default. You have to ask permission to Facebook for you to be able to use that information. Add a video and instructions for a Facebook employee review how you're using birthday and hometown intel.

How do you get a list of pages a user has created and how do you post to a particular page

I am obviously missing something here. I can successfully login to FB and can access all of the user data. However I see no references on how to work with the users pages that they have created and then allow them to post to the pages.
I am wanting to allow the user to choose which of his pages he wants to post to and then post to them.
So here is what I am dealing with in the code, I am successfully logged on and can post to my wall. Here is the code I am using at that point to get the list of
NSArray *pagePermissionsNeeded = #[#"manage_pages"];
[FBRequestConnection startWithGraphPath:#"/me/accounts"
completionHandler:^(FBRequestConnection *connection, id result, NSError *error) {
if (!error){
NSDictionary *currentPermissions= [(NSArray *)[result data] objectAtIndex:0];
NSMutableArray *requestPermissions = [[NSMutableArray alloc] initWithArray:#[]];
for (NSString *permission in pagePermissionsNeeded){
if (![currentPermissions objectForKey:permission]){
[requestPermissions addObject:permission];
}
}
if ([requestPermissions count] > 0){
[FBSession.activeSession requestNewPublishPermissions:requestPermissions
defaultAudience:FBSessionDefaultAudienceFriends
completionHandler:^(FBSession *session, NSError *error) {
if (!error) {
[self functiontoListPages];
} else {
NSLog(#"%#", error.description);
}
}];
} else {
[self functiontoListPages];
}
} else {
NSLog(#"%#", error.description);
}
}];
I used the code from th Facebook samples as my starting point and a trying to figure it out. I still have yet to be able to find anything outside of FB to give samples or tutorials.
You need to gather the manage_pages permission in the OAuth process to be able to do this. Then, you can get the Page Access Tokens by requesting
/me/accounts
for the relevant user. See docs at https://developers.facebook.com/docs/facebook-login/permissions#reference-pages

Filling my model from Facebook data (<FBGraphUser>)

I created a model called User that have a property "name".
I'm making a request to facebook API (using the latest iOS SDK), the idea is set my user.name property when the facebook return the data.
The facebook return the data into the startWithCompletionHandler block, but I can't set this data to my user object, I only can access the data on startWithCompletionHandler. When I try access the data out of the block my model returns NULL.
How can I fill my model/object when facebook request returns?
My current method implementation:
+ (void)requestUserData:(User *)userModel {
if(FBSession.activeSession.isOpen) {
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if(user.name) [self setUserData:user userModel:userModel];
}];
}
}
+ (void)setUserData:(NSDictionary<FBGraphUser> *)user userModel:(User *)userModel {
userModel.name = user.name;
}
And the call:
__block User *user = [[User alloc] init];
[GFFacebookHelpers requestUserData:user];
NSLog(#"user: %#", user.name); //this part prints 2013-06-06 18:03:43.731 FacebookClassTest[74172:c07] user: (null)
Thanks.
The Facebook's SDK is fetching asynchronously, so the completion handler you've written is executed after your helper method returns.
So when your method returns the User object of yours it is, logically just an empty user (since you alloc/init'ed it already).
When the completion block is invoked, that user object is updated but by this time, you're not processing it anymore in your app (view controller).
So here is my suggestion: Either use the Facebook SDK more directly from your view controllers, or if you want to keep all this logic in your helper class, then change it so your method doesn't return data, but it requires a block which will be invoked when the data request has finished, something more like this:
+ (void)requestUserDataWithCompletionHandler:(void (^)(User *user, NSError *error))handler{
if(FBSession.activeSession.isOpen) {
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection, NSDictionary<FBGraphUser> *user, NSError *error) {
if(!error){
User *userData = [[User alloc] init];
userData.name = user.name;
dispatch_async(dispatch_get_main_queue(), ^{
handler(userData, nil);
});
}
else{
dispatch_async(dispatch_get_main_queue(), ^{
handler(nil, error);
});
}
}];
}
}
Note I've wrapped the invocation of the handler block in a dispatch_async() to the main queue to make sure you're good to go to update any UI.
Your view controller's method will now look like this:
- (void)updateStatusLabels {
if([GFFacebookHelpers isLogged]){
[GFFacebookHelpers requestUserDataWithCompletionHandler:^(User *user, NSError *error) {
if(!error){
self.fbStatus.text = user.name;
[_loginButton setTitle:#"Logout" forState:UIControlStateNormal];
}
}];
}else{
self.fbStatus.text = #"You need to login";
[_loginButton setTitle:#"Login" forState:UIControlStateNormal];
}
}

Facebook SDK FBGraphUser can't store local copy

I've started Facebook integration for a project and I've run into a problem. I am attempting to store the logged in user as a local object so the information can be referenced later, but I can't seem to hold onto the information.
Here is my function for fetching the user data:
if(_session.isOpen)
{
[FBSession openActiveSessionWithReadPermissions:nil
allowLoginUI:YES
completionHandler:^(FBSession *session,
FBSessionState state,
NSError *error)
{
[[FBRequest requestForMe] startWithCompletionHandler:^(FBRequestConnection *connection,
NSDictionary<FBGraphUser> *user,
NSError *error)
{
if(!error)
{
NSLog(#"Username: %#",user.name);
[_user initWithDictionary:user];
NSLog(#"Username: %#",[_user objectForKey:#"name"]);
}
else
{
NSLog(#"Couldn't get user details!");
}
}];
}];
}//endif
In this case, the NLog gives "Username: (null)"
I'm pretty new to both ObjC and Facebook so I'm not sure what I'm doing wrong. Also, I tried to create a member variable :
#property (strong, nonatomic) NSDictionary<FBGraphUser> *loggedInUser;
and previously my code for storing the user was
if(!error)
{
NSLog(#"Username: %#",user.name);
_user = user;
NSLog(#"Username: %#", _user.name);
}
else
{
NSLog(#"Couldn't get user details!");
}
Since neither of these worked (the second worked insofar as the second NSLog gave the correct variable, but later attempts to access it outside this function caused a crash) I can only assume I am not storing the information correctly.
Can someone give me some pointers on what I'm doing wrong?
You need to print user.username not user.name

Resources