Класс Facebook Connect с Singleton: проблема с токеном доступа - PullRequest
3 голосов
/ 17 августа 2011

Я создал одноэлементный класс «LoginFacebook», предназначенный для подключения пользователя к Facebook и выполнения другого запроса.Проблема в том, что я получаю сообщение об ошибке access_token.Вот оно:

3 : <CFString 0x4c552f0 [0xe50400]>{contents = "message"} = <CFString 0x4c55250 [0xe50400]>{contents = "An active access token must be used to query information about the current user."}

Сначала я подключаюсь к Facebook, делая следующий запрос от другого View Controller:

[[LoginFacebook loginFacebook] launchFacebook:self]

Затем я делаю второй запрос от того же другого View Controller, ноиз другого метода:

[[LoginFacebook loginFacebook] requireName:self]

Вот мой синглтон-класс "LoginFacebook":

LoginFacebook.h :

#import <UIKit/UIKit.h>
#import "LoginFacebook.h"

@interface FirstViewController : UIViewController {

}

-(IBAction)performConnect:(id)sender;
-(IBAction)performName:(id)sender;

@end

LoginFacebook.m:

#import "LoginFacebook.h"
static LoginFacebook *loginFacebook = nil;

@implementation LoginFacebook
@synthesize name;
@synthesize facebook;

-(void)launchFacebook:(id)sender
{ 

permissions =  [[NSArray arrayWithObjects:
@"read_stream", @"publish_stream", @"offline_access",nil] retain];

Facebook* facebookbis = [[Facebook alloc] initWithAppId:@"168938499825684"];
facebook = facebookbis;
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if ([defaults objectForKey:@"FBAccessTokenKey"]
&& [defaults objectForKey:@"FBExpirationDateKey"]) {
facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
}
if (![facebook isSessionValid]) {
[facebook authorize:nil delegate:self];
}
}

-(NSString *)requireName:(id)sender
{
NSLog(@"requireName asked");
[facebook requestWithGraphPath:@"me" andDelegate:self];
return name;
NSLog(@"%@",[facebook accessToken]);
}


+ (LoginFacebook *)loginFacebook
{
if (loginFacebook == nil) {
loginFacebook = [[super allocWithZone:NULL] init];
}
return loginFacebook;
}

+ (id)allocWithZone:(NSZone *)zone {
return [[self loginFacebook] retain];
}

- (id)copyWithZone:(NSZone *)zone {
return self;
}

- (id)retain {
return self;
}

- (NSUInteger)retainCount {
return NSUIntegerMax;  //denotes an object that cannot be released
}

- (void)release {
//do nothing
}

- (id)autorelease {
return self;
}

// FBRequestDelegate

/**
* Called when the Facebook API request has returned a response. This callback
* gives you access to the raw response. It's called before
* (void)request:(FBRequest *)request didLoad:(id)result,
* which is passed the parsed response object.
*/
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response {
NSLog(@"received response");
}

/**
* Called when a request returns and its response has been parsed into
* an object. The resulting object may be a dictionary, an array, a string,
* or a number, depending on the format of the API response. If you need access
* to the raw response, use:
*
* (void)request:(FBRequest *)request
*      didReceiveResponse:(NSURLResponse *)response
*/
- (void)request:(FBRequest *)request didLoad:(id)result {
if ([result isKindOfClass:[NSArray class]]) {
result = [result objectAtIndex:0];
}
name = [result objectForKey:@"name"];
NSLog(@"request didLoad");
};

/**
* Called when an error prevents the Facebook API request from completing
* successfully.
*/
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error {
name = [error localizedDescription];
NSLog(@"----request didFailWithError");
NSLog(@"%@", [error localizedDescription]);
NSLog(@"%@", [error description]);
};


////////////////////////////////////////////////////////////////////////////////
// FBDialogDelegate

/**
* Called when a UIServer Dialog successfully return.
*/
- (void)dialogDidComplete:(FBDialog *)dialog {
name = @"publish successfully";
}

@end

Обратите внимание, что я добавилследующий метод (с соответствующим FacebookLogin * facebook в .h) моему делегату приложения:

- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url {

return [facebook handleOpenURL:url];
}

Кто-нибудь из вас знает, что там происходит не так?Я борюсь с кодом уже 2 дня ...

1 Ответ

2 голосов
/ 17 августа 2011

Из сообщения об ошибке кажется, что ваш токен доступа больше не действителен или у вас еще не было токена доступа.Открывает ли ваше приложение веб-браузер в первый раз, когда пользователь пытается получить доступ к Facebook?Если нет, то вам, вероятно, не удалось правильно настроить проект.

Возможно, было бы неплохо поделиться кодом моего синглтона Facebook - я считаю, что код довольно чистый, его легко понять и расширить.Поскольку мои потребности в настоящее время очень скромны, у меня есть только один метод авторизации (логин) и другой метод для публикации на стене.Я использую стек, чтобы я мог выполнять некоторые операции в правильном порядке (например, войти в систему до публикации сообщения на стене, если пользователь еще не вошел в систему).

SDFacebookController.h

#import <Foundation/Foundation.h>
#import "FBConnect.h"

@interface SDFacebookController : NSObject 
   <FBSessionDelegate, 
   FBRequestDelegate>

@property (nonatomic, retain) Facebook *facebook;

+ (SDFacebookController *)sharedController;
- (void)authorize;
- (void)postMessageToWall:(NSString *)message;
@end

SDFacebookController.m

#import "SDFacebookController.h"
#import "Constants+Macros.h"
#import "SDOperationStack.h"


@interface SDFacebookController ()
@property (nonatomic, retain) SDOperationStack *operationStack;
- (void)performAuthorization;
- (void)performPostMessageToWall:(NSString *)message;
- (void)runOperation;
@end


@implementation SDFacebookController
@synthesize facebook, operationStack;

#pragma mark - Instance methods

- (void)authorize
{
   NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performAuthorization) object:nil] autorelease];
   [operationStack push:operation];

   [self runOperation];
}

- (void)postMessageToWall:(NSString *)message 
{   
   NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performPostMessageToWall:) object:message] autorelease];
   [operationStack push:operation];

   if (![facebook isSessionValid])
   {
      NSInvocationOperation *operation = [[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(performAuthorization) object:nil] autorelease];
      [operationStack push:operation];
   }

   [self runOperation];
}

#pragma mark - Private methods 

- (void)runOperation
{
   NSOperation *operation = [operationStack pop];
   [[NSOperationQueue currentQueue] addOperation:operation];
}

- (void)performAuthorization
{
   if (![facebook isSessionValid]) 
   {
      NSArray *permissions = [NSArray arrayWithObject:@"publish_stream"];
      [facebook authorize:permissions delegate:self];
   }
}

- (void)performPostMessageToWall:(NSString *)message 
{
   NSMutableDictionary *params = [NSMutableDictionary dictionaryWithObjectsAndKeys:message, @"message", nil];
   [facebook requestWithGraphPath:@"me/feed" andParams:params andHttpMethod:@"POST" andDelegate:self];
}

#pragma mark - FBRequestDelegate

/**
 * Called just before the request is sent to the server.
 */
- (void)requestLoading:(FBRequest *)request
{
   DLog(@"%@", request);
}

/**
 * Called when the server responds and begins to send back data.
 */
- (void)request:(FBRequest *)request didReceiveResponse:(NSURLResponse *)response
{
   DLog(@"%@ %@", request, response);
}

/**
 * Called when an error prevents the request from completing successfully.
 */
- (void)request:(FBRequest *)request didFailWithError:(NSError *)error
{
   DLog(@"%@ %@", request, error);

   [[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"Error", nil) 
                                message:[error localizedDescription] 
                               delegate:nil 
                      cancelButtonTitle:NSLocalizedString(@"OK", nil) 
                      otherButtonTitles:nil] 
     autorelease] show];

   [operationStack empty];
}

/**
 * Called when a request returns and its response has been parsed into
 * an object.
 *
 * The resulting object may be a dictionary, an array, a string, or a number,
 * depending on thee format of the API response.
 */
- (void)request:(FBRequest *)request didLoad:(id)result
{
   DLog(@"%@ %@", request, result);

   if ([operationStack isEmpty] == NO)
      [self runOperation];
   else if ([operationStack.lastOperation.invocation selector] == @selector(performPostMessageToWall:))
      [[[[UIAlertView alloc] initWithTitle:NSLocalizedString(@"MessagePosted", nil) 
                                   message:NSLocalizedString(@"Successfully posted message on Facebook.", nil) 
                                  delegate:nil 
                         cancelButtonTitle:NSLocalizedString(@"OK", nil) 
                         otherButtonTitles:nil] 
        autorelease] show];
}

/**
 * Called when a request returns a response.
 *
 * The result object is the raw response from the server of type NSData
 */
- (void)request:(FBRequest *)request didLoadRawResponse:(NSData *)data
{
   DLog(@"%@ %@", request, data);
}

#pragma mark - FBSessionDelegate

/**
 * Called when the user successfully logged in.
 */
- (void)fbDidLogin 
{
   NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
   [defaults setObject:[facebook accessToken] forKey:@"FBAccessTokenKey"];
   [defaults setObject:[facebook expirationDate] forKey:@"FBExpirationDateKey"];
   [defaults synchronize];
}

/**
 * Called when the user dismissed the dialog without logging in.
 */
- (void)fbDidNotLogin:(BOOL)cancelled
{

}

/**
 * Called when the user logged out.
 */
- (void)fbDidLogout
{

}

#pragma mark - Memory management 

- (id)init 
{
   self = [super init];
   if (self)
   {      
      facebook = [[Facebook alloc] initWithAppId:kFacebookAppIdentifier];
      operationStack = [[SDOperationStack alloc] init];

      NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
      if ([defaults objectForKey:@"FBAccessTokenKey"] && [defaults objectForKey:@"FBExpirationDateKey"]) 
      {
         facebook.accessToken = [defaults objectForKey:@"FBAccessTokenKey"];
         facebook.expirationDate = [defaults objectForKey:@"FBExpirationDateKey"];
      }
   }
   return self;
}

- (void)dealloc 
{
   [operationStack release];
   [facebook release];
   [super dealloc];
}

#pragma mark - Singleton

+ (SDFacebookController *)sharedController
{
   static SDFacebookController *controller = nil;

   static dispatch_once_t onceToken;
   dispatch_once(&onceToken, ^{
      controller = [[self alloc] init];
   });

   return controller;   
}

@end

SDOperationStack.h

#import <Foundation/Foundation.h>

@interface SDOperationStack : NSObject

@property (nonatomic, retain) NSInvocationOperation *lastOperation;

- (void)push:(NSOperation *)operation;
- (NSOperation *)pop;
- (BOOL)isEmpty;
- (void)empty;

@end

SDOperationStack.m

#import "SDOperationStack.h"


@interface SDOperationStack ()
@property (nonatomic, retain) NSMutableArray *array;
@end


@implementation SDOperationStack
@synthesize array, lastOperation;

- (void)dealloc 
{
   [lastOperation release];
   [array release];
   [super dealloc];
}

- (id)init
{
    self = [super init];
    if (self) 
    {
       array = [[NSMutableArray alloc] init];
    }
    return self;
}

- (void)push:(NSInvocationOperation *)operation
{
   [array addObject:operation];
}

- (NSInvocationOperation *)pop
{
   if ([self isEmpty]) 
        return nil;

   self.lastOperation = (NSInvocationOperation *)[array lastObject];
   [array removeLastObject];
   return lastOperation;
}

- (BOOL)isEmpty 
{
   return [array count] == 0;
}

- (void)empty 
{
   [array removeAllObjects];
}

@end
...