Handle ACAccountStoreDidChangeNotification for Facebook & Twitter in iOS 6+

淺唱寂寞╮ 提交于 2019-12-08 06:24:07

问题


I am using Social framework for Facebook & Twitter integration. For this I followed this link Everything is working fine except when I app receives ACAccountStoreDidChangeNotification , it crashes. App crashes when

1) I installed app for first time & user don't have Facebook / Twitter account configured in Settings.

2) When I call any method of Facebook / Twitter , it gives me error code 6 as I don't have account configured which is right.

3) I click on HOME button so my app enters background & add account in Settigs.

4) Once I configured account & come back to app , my app launches from background & receives ACAccountStoreDidChangeNotification.

5) In selector of ACAccountStoreDidChangeNotification my account object is nil so my app crashes. So I checked for the nil

Here is my code

    #pragma mark - Request Facebook Account Access

-(void)requestFacebookAccountAccess
{
    requestType = kNoOpRequest;
    //  Register for Account Change notification
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(accountChanged:) name:ACAccountStoreDidChangeNotification object:nil];

    self.accountStore = [[ACAccountStore alloc]init];
    ACAccountType *FBaccountType= [self.accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierFacebook];

    // Set facebook permissions
    NSArray *permissions = nil;

    // We need to ask for Basic permission first
    if (![kUserDefaults boolForKey:FACEBOOK_BASIC_PERMISSION]) {
        permissions = @[@"email",@"user_about_me",@"user_location",@"friends_about_me"];
        self.isBasicFacebookPermissionsRequested = YES;
    }
    else {
        permissions = @[@"email",@"user_about_me",@"user_location",@"friends_about_me",@"publish_stream"];
    }

    //use ACAccountStore to help create your dictionary
    NSDictionary *dictFacebook = @{
        ACFacebookAppIdKey: kFacebookAppIDKey,
        ACFacebookPermissionsKey: permissions,
        ACFacebookAudienceKey: ACFacebookAudienceFriends
    };

    [self.accountStore requestAccessToAccountsWithType:FBaccountType options:dictFacebook completion:^(BOOL granted, NSError *error) {
        if (granted) {

            if (self.isBasicFacebookPermissionsRequested) {
                self.isBasicFacebookPermissionsRequested = NO;
                [kUserDefaults saveBasicFacebookPermissionsGrantedStatus:YES];
                //[self requestFacebookAccountAccess];
            }

            // User granted permission to Accout
            NSArray *accountsArray = [self.accountStore accountsWithAccountType:FBaccountType];

            if ([accountsArray count]>0) {
                //It will always be the last object with SSO
                self.facebookAccount = [accountsArray lastObject];
                NSLog(@"In %s::IS MAIN THREAD:- %@",__PRETTY_FUNCTION__,[NSThread isMainThread]?@"YES":@"NO");

                if ([self.delegate respondsToSelector:@selector(didFacebookAccountAccessGranted)]) {
                        dispatch_async(dispatch_get_main_queue(),^{
                            [self.delegate didFacebookAccountAccessGranted];
                        });
                }
            }
            else {
                [self showAlertWithTitle:@"Error" andMessage:@"You don't have any Facebook accounts set up yet.Please set a Facebbok account and try again."];
            }
        }
        else {
            DLog(@"User denied permission to Accout::Localized Error:- %@",error.localizedDescription);
            if([error code]==6) {
                [self showAlertWithTitle:@"Error" andMessage:@"Please setup facebook account from Settings"];
                if ([self.delegate respondsToSelector:@selector(didFacebookAccountAccessDenied:)]) {
                    dispatch_async(dispatch_get_main_queue(),^{
                        [self.delegate didFacebookAccountAccessDenied:error];
                    });
                }
            }
            else if ([self.delegate respondsToSelector:@selector(didFacebookAccountAccessDenied:)]) {
                dispatch_async(dispatch_get_main_queue(),^{
                    [self.delegate didFacebookAccountAccessDenied:error];
                });
            }

            else {
                // User denied permission to Account
                [self showAlertWithTitle:@"Error" andMessage:[NSString stringWithFormat:@"User denied permission to Accout::Error:- %@",error.localizedDescription]];
            }
        }
    }];
}



#pragma mark - Get Logged In User Info

-(void)getLoggedInUserInfo
{
    NSURL *requestURL = [NSURL URLWithString:@"https://graph.facebook.com/fql"];
    NSDictionary *dict = [NSDictionary dictionaryWithObjectsAndKeys:@"SELECT current_location,uid,name,sex,birthday,email,pic FROM user WHERE uid=me()",@"q", nil];
    requestType = kGetLoggedInUserInfoRequest;
    [self requestDataUsingURL:requestURL parameters:dict requestMethod:SLRequestMethodGET];
}

#pragma mark - Request Data From Facebook

-(void)requestDataUsingURL:(NSURL*)requestURL parameters:(NSDictionary*)params requestMethod:(SLRequestMethod)reuqestMethod
{

    SLRequest *request = [SLRequest requestForServiceType:SLServiceTypeFacebook
                                            requestMethod:reuqestMethod
                                                      URL:requestURL
                                               parameters:params];
    request.account = self.facebookAccount;

    [request performRequestWithHandler:^(NSData *data,
                                         NSHTTPURLResponse *response,
                                         NSError *error)
     {
         NSDictionary *dictData =[NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
         if(!error)
         {
             if([dictData objectForKey:@"error"]!=nil)
             {
                 DLog(@"Request Data From Facebook Errro:- %@",dictData);
                 [self attemptRenewCredentials];
                 if ([self.delegate respondsToSelector:@selector(didGetFacebookError:)]) {
                     dispatch_async(dispatch_get_main_queue(),^{
                         [self.delegate didGetFacebookError:dictData];
                     });
                 }
             }
             else {
                // Process the response
                //NSLog(@"Response Dictionary contains: %@", dictData );
                if ([self.delegate respondsToSelector:@selector(didPostToFacebook:)]) {
                     dispatch_async(dispatch_get_main_queue(),^{
                         [self.delegate didPostToFacebook:dictData];
                     });
                }
             }
         }
         else{
             if ([self.delegate respondsToSelector:@selector(didGetFacebookError:)]) {
                 dispatch_async(dispatch_get_main_queue(),^{
                     [self.delegate didGetFacebookError:dictData];
                 });
             }
             else {
                 [self showAlertWithTitle:@"Error" andMessage:@"Some error occured while processing Facebook request"];
             }
         }

     }];
}

-(void)accountChanged:(NSNotification *)notif
{
    if (self.facebookAccount!=nil) {
        [self attemptRenewCredentials];
    }
    else {
        [self requestFacebookAccountAccess];
    }
}

#pragma mark - Attempt to Renew Credentials

-(void)attemptRenewCredentials
{
    [self.accountStore renewCredentialsForAccount:(ACAccount *)self.facebookAccount completion:^(ACAccountCredentialRenewResult renewResult, NSError *error){
        if(!error)
        {
            switch (renewResult) {
                case ACAccountCredentialRenewResultRenewed:
                    NSLog(@"Good to go");
                    [self againRequestFacebook];
                    break;
                case ACAccountCredentialRenewResultRejected:
                    NSLog(@"User declined permission");
                    break;
                case ACAccountCredentialRenewResultFailed:
                    NSLog(@"non-user-initiated cancel, you may attempt to retry");
                    break;
                default:
                    break;
            }

        }
        else{
            //handle error gracefully
            NSLog(@"error from renew credentials%@",error);
        }
    }];
}

-(void)againRequestFacebook
{
    switch (requestType) {
        case kGetLoggedInUserInfoRequest:
            [self getLoggedInUserInfo];
            break;
        case kGetFriendsInfoRequest:
            [self getFacebookFriendsInfo];
            break;
        case kPostToWallRequest:
            [self postToFacebookWallInBackgroundForUserId:fbUserIdForPost withParams:paramsToPost];
            break;
        default:
            break;
    }
}

#pragma mark - Remove Observer for Notification

-(void)dealloc
{
    requestType = kNoOpRequest;
    [[NSNotificationCenter defaultCenter] removeObserver:ACAccountStoreDidChangeNotification];
}

But accountChanged method gets called multiple times. What is wrong in this ? How can I handle this situation ? Any kind of help is highly appreciated.

Thanks in advance.


回答1:


I am facing the same problem...so i used a work around by having a BOOL value in NSUserDefaults to execute accountChanged method only once

-(void)accountChanged:(NSNotification *)notif
{
    BOOL calledAccountChanged =[[[NSUserDefaults standardUserDefaults] objectForKey:DidAccountChanged] boolValue];
    if(!calledAccountChanged)
    {
        if (self.facebookAccount!=nil) {
            [self attemptRenewCredentials];
        }
        else {
            [self requestFacebookAccountAccess];
        }
    }
}

Then we can change DidAccountChanged value later in the code...

If you have better solution do post it...



来源:https://stackoverflow.com/questions/14982622/handle-acaccountstoredidchangenotification-for-facebook-twitter-in-ios-6

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!