Become a MacRumors Supporter for $50/year with no ads, ability to filter front page stories, and private forums.

newtoiphonesdk

macrumors 6502a
Original poster
Jul 30, 2010
567
2
There essentially two main things that can cause issues when using SLRequest for making Facebook posts: 1. The user removes permissions for the app on Facebook. This causes an error 2500 that means you have to 're-install' the app and get permissions all over again. 2. The token has expired. All you have to do here is renew the credentials.

My issue is mainly with the first one. I have been able to handle renewing credentials, but I run into much difficulty when trying to 'renewbigtime' (how I like to call it)or re-install the app and obtain permissions again.

Here is the layout of my facebook posting code (see comments for explanations of why I do it this way):

First, the user has to toggle on facebook sharing in the Settings View Controller:
Code:
-(void)facebookpost {
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];

       ACAccountType * facebookAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    NSArray *accounts = [accountStore accountsWithAccountType:facebookAccountType];

  //why two permissions and dictionaries?  Well, before you can post to Facebook, you have to get basic read permissions, such as email.  If you attempt to obtain both of these permissions, you will fail.  So, the app tries for permission of email first, if it succeeds, it tries for permission for publish_stream.  
    NSArray * permissions = @[@"email"];
    NSArray * permissions2 = @[@"publish_stream"];

    NSDictionary * dict = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions, ACFacebookAudienceKey : ACFacebookAudienceFriends};
    NSDictionary * dict2 = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions2, ACFacebookAudienceKey : ACFacebookAudienceFriends};
    [accountStore requestAccessToAccountsWithType:facebookAccountType options:dict completion:^(BOOL granted, NSError *error) {
        if (granted && error == nil) {
//the following defaults just sets a key value which will be checked to see if the app should try and post anything
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"facebook"];
            [[NSUserDefaults standardUserDefaults] synchronize];
           //nothing gets posted yet, onto try for permissions to post

            [accountStore requestAccessToAccountsWithType:facebookAccountType options:dict2 completion:^(BOOL granted, NSError *error) {
                if(granted && error == nil) {

                  //good, it is now granted permission for both reading and writing
                } else {
                    NSLog(@"1error is: %@",[error description]);
                }
            }];
        } else {

            NSLog(@"error is: %@",error );

            if(error.code == 6){
//this is the error message that will appear if the user has not signed into Facebook from Settings app.  alertmessage simply pops up an alert instructing them to please do so.
                [self performSelectorOnMainThread:@selector(alertmessage)
                                       withObject:nil
                                    waitUntilDone:YES];                }
        }
    }];

}
Now, we are onto the posting code. This code is in the Detail View Controller of the Table View. The table view lists the articles, clicking on one displays it in the Detail View using a webView. In the viewWillAppear, the app checks for the bool value of the 'facebook' key. If it is NO, it does nothing more than show the article. If it is YES, it tries to post to the wall with (once again see comments for explanations):
Code:
-(void)writetowall {
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];

    ACAccountType *accountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    NSArray *accounts = [accountStore accountsWithAccountType:accountType];

    ACAccount *account = [accounts lastObject];

      NSDictionary *parameters = @{@"message" : [NSString stringWithFormat:@"I'm reading %@ from the blog.  Click the link to read it too.", _entry.articleTitle], @"link": _entry.articleUrl};
    NSURL *URL = [NSURL URLWithString:@"https://graph.facebook.com/me/feed"];

    SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook
                                            requestMethod:SLRequestMethodPOST
                                                      URL:URL
                                               parameters:parameters];


    [request setAccount:account];

    [request performRequestWithHandler:^(NSData *responseData,
                                             NSHTTPURLResponse *urlResponse, NSError *error) {
        NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:responseData
                                                                           options:kNilOptions
                                                                            error:&error];
        NSDictionary *errorDictionary = [responseDictionary valueForKey:@"error"];

        if (errorDictionary) {

            NSNumber *errorCode = [errorDictionary valueForKey:@"code"];
            if ([errorCode isEqualToNumber:[NSNumber numberWithInt:190]]) {
//190 is code that you need to renew credentials.  this is when tokens expire.  so, if it happens, it goes to renew code (not included in this question as it is working fine)
            NSLog(@"Renew");
                [self renew];
            }
            if ([errorCode isEqualToNumber:[NSNumber numberWithInt:2500]]) {
//here is the 2500 code meaning the app has not been installed yet, or needs to be installed again with new permissions.  so, I have it run the method renewbigtime which I will now list below
                [self renewbigtime];
            }
        }
    }];
}
Ok, so the user goes to Facebook AppCenter, clicks the X next to the app, and now when they try to post, it gives them error code 2500, so it triggers this method, which is very similar to the initial method to grant initial permissions:
Code:
-(void)renewbigtime {
    ACAccountStore *accountStore = [[ACAccountStore alloc] init];

    ACAccountType * facebookAccountType = [accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];
    NSArray *accounts = [accountStore accountsWithAccountType:facebookAccountType];

    NSArray * permissions = @[@"email"];
    NSArray * permissions2 = @[@"publish_stream"];

    NSDictionary * dict = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions, ACFacebookAudienceKey : ACFacebookAudienceFriends};
    NSDictionary * dict2 = @{ACFacebookAppIdKey : @"289006474446717", ACFacebookPermissionsKey : permissions2, ACFacebookAudienceKey : ACFacebookAudienceFriends};
    [accountStore requestAccessToAccountsWithType:facebookAccountType options:dict completion:^(BOOL granted, NSError *error) {
        if (granted && error == nil) {
            [[NSUserDefaults standardUserDefaults] setBool:YES forKey:@"facebook"];
            [[NSUserDefaults standardUserDefaults] synchronize];


            [accountStore requestAccessToAccountsWithType:facebookAccountType options:dict2 completion:^(BOOL granted, NSError *error) {
                if(granted && error == nil) {
                    //here is where it should be granted and no errors for anything, so we redirect to writetowall method which should simply post to the wall
                    [self writetowall];
                } else {
                    NSLog(@"1error is: %@",[error description]);
                }
            }];
        } else {

            NSLog(@"error is: %@",error );

            if([[error description] isEqualToString:@"Error Domain=com.apple.accounts Code=6 \"The operation couldn’t be completed. (com.apple.accounts error 6.)\""]){
                [self performSelectorOnMainThread:@selector(alertmessage)
                                       withObject:nil
                                    waitUntilDone:YES];                }
        }
    }];

}
The problem is that the app gets stuck in a loop at this point. If it gets error 2500, it tries to renew credentials, but keeps on going through with error 2500, try to renew, 2500, try to renew. No other error messages get triggered in the renewbigtime section, so what am I doing wrong?
 
Last edited:
Register on MacRumors! This sidebar will go away, and you'll see fewer ads.