How to use Facebook Graph API on iOS properly
I am making an application where I need to invoke requests in multiple view controllers. I don't want the Facebook log in screen to show when the app is launched. It should only open when the user taps a button in another view controller if the user is not logged in, so putting the code in app delegate is not working solution to the problem. And the whole asynchronous process of requesting data in the Facebook API is killing me, I am starting to loose hair.
A class with static methods to get the facebook object and treat it as a singleton.
#import "PBSocialMedia.h"
#import "PBFacebookDelegate.h"
static Facebook *facebook;
static PBFacebookDelegate *facebookDelegate;
@implementation PBSocialMedia
+ (Facebook *)sharedFacebook {
if (facebook == nil) {
facebookDelegate = [[PBFacebookDelegate alloc] init];
facebook = [[Facebook alloc] initWithAppId:@"156687441079334" andDelegate:facebookDelegate];
}
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:@"FBAccessTokenKey"]
&& [defaults objectForKey:@"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
}
NSArray *permissions = [NSArray arrayWithObjects:@"user_photo_video_tags", @"friends_photo_video_tags", @"user_photos", @"friends_photos", nil];
if (![facebook isSessionValid]) {
[facebook authorize:permissions];
} else {
[[NSNotificationCenter defaultCenter] postNotificationName:@"connectedToFacebook" object:self];
}
return facebook;
}
+ (Facebook *)sharedFacebookWithoutAuthorizing {
return facebook;
}
@end
A class that implements the Facebook session delegate used in the class above
#import "PBFacebookDelegate.h"
#import "PBSocialMedia.h"
@implementation PBFacebookDelegate
/**
* Called when the user successfully logged in.
*/
- (void)fbDidLogin {
Facebook *facebook = [PBSocialMedia sharedFacebook];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
[defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
[defaults synchronize];
[[NSNotificationCenter defaultCenter] postNotificationName:@"connectedToFacebook" object:self];
}
/**
* Called when the user dismissed the dialog without logging in.
*/
- (void)fbDidNotLogin:(BOOL)cancelled {
[[NSNotificationCenter defaultCenter] postNotificationName:@"dismissedFacebookDialog" object:self];
}
/**
* Called when the user logged out.
*/
- (void)fbDidLogout {
[[NSNotificationCenter defaultCenter] postNotificationName:@"disconnectedFromFacebook" object:self];
}
@end
As you see from the two classes above I am making use of notifications so that I know when the user logs in/out of Facebook. The code below is an example of how I am trying to use it:
- (void)viewDidLoad {
[super viewDidLoad];
Facebook *facebook = [PBSocialMedia sharedFacebook];
if (self.canUseGraphAPI) {
[facebook requestWithGraphPath:@"106378916135129/photos" andDelegate:self];
NSLog(@"Can use");
} else {
NSLog(@"Can't use");
}
}
- (void)connectedToFacebook {
self.canUseGraphAPI = YES;
}
- (void)disconnectedFromFacebook {开发者_运维技巧
self.canUseGraphAPI = NO;
}
This is ofcourse NOT working as intended because of the stupid asynchronous request. It will work correct only when the user is logged in. So the first time I open the app it invokes the [PBSocialMedia sharedFacebook];
Then it proceed with the request function AND NOT waiting for the sharedFacebook function to finish. I really hope somebody has encountered this problem before. I want to do requests in different places in my code, but only when the user is logged in, and it need to WAIT while the user logs in before requesting. The code below is not working but it shows what I want!
- (void)viewDidLoad {
[super viewDidLoad];
Facebook *facebook = [PBSocialMedia sharedFacebook];
while (self.canUseGraphAPI) {
// WAITING FOR LOGIN IN
}
[facebook requestWithGraphPath:@"106378916135129/photos" andDelegate:self];
}
- (void)connectedToFacebook {
self.canUseGraphAPI = YES;
}
- (void)disconnectedFromFacebook {
self.canUseGraphAPI = NO;
}
I would start restructuring your code to work by passing in blocks that you want executed upon getting your answer back from FB. This is similar to how you do ajax in JQuery.
- (void)viewDidLoad {
[super viewDidLoad];
Facebook *facebook = [PBSocialMedia sharedFacebook];
[self withGraphAPIDo: ^{
[facebook requestWithGraphPath:@"106378916135129/photos" andDelegate:self];
}];
}
精彩评论