iOS Super slow Twitter sign in - basically unusable!


#1

First apologise for this code dump. But this twitter sign is unsable, takes up to a minute to display the action sheet to select the account.

Not sure if any of the developers can help but I am at a point where I am going to have to remove twitter from my iOS app.

-(void) loginTwitter {
	
    if(![[StateModel stateModel] startedTwitterLogin]){
    	[self showListOfTwitterAccountsFromStore];
		[[StateModel stateModel] setStartedTwitterLogin:YES];
	}
    
}
- (void)showListOfTwitterAccountsFromStore
{
	[[ActivityIndicator currentIndicator] displayActivity:LocalizedString(@"Loading Twitter accounts") ];
    //  First, we need to obtain the account instance for the user's Twitter account
	ACAccountStore *store = [[ACAccountStore alloc] init];
	ACAccountType *twitterAccountType =
	[store accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
	
	//  Request permission from the user to access the available Twitter accounts
	[store requestAccessToAccountsWithType:twitterAccountType options:nil completion:^(BOOL granted, NSError *error) {
		
         if(granted) {
             
             _accountStore = [[ACAccountStore alloc] init];
             _accountStore=store;
			 _twitterAccountType=twitterAccountType;
            
			[self willDisplayTwitterActionSheet];
		} else {
			// not granted
			[[StateModel stateModel] setStartedTwitterLogin:NO];
			[[ActivityIndicator currentIndicator] hideAfterDelay];
		}
     }];
    
}

-(void) willDisplayTwitterActionSheet
{
	NSMutableArray *twitterUsers=[[NSMutableArray alloc] init];
	twitterUsers=[[DataModel dataModel] twitterUsers];
	UIActionSheet *actions = [[UIActionSheet alloc] initWithTitle:@"Choose Account to Use" delegate:self cancelButtonTitle:@"Cancel" destructiveButtonTitle:nil otherButtonTitles:nil];
	//actions.actionSheetStyle=UIActionSheetStyleBlackTranslucent;
	actions.tag = 2;
	NSArray *userAccounts= [_accountStore accountsWithAccountType:_twitterAccountType];
	for (ACAccount * account in userAccounts) {
		[actions addButtonWithTitle:account.username];
		[twitterUsers addObject:account];
	}
	actions.actionSheetStyle = UIActionSheetStyleDefault;
	//[actions set]
	[UIActionSheet setAnimationDelay:0];
	[UIActionSheet setAnimationDuration:0.1];
	[actions showInView:[UIApplication sharedApplication].keyWindow];

}

-(void) willPresentActionSheet:(UIActionSheet *)actionSheet
{
    [[ActivityIndicator currentIndicator] hide];

}

-(void) actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
    ACAccountType *accountType = [_accountStore accountTypeWithAccountTypeIdentifier:ACAccountTypeIdentifierTwitter];
    NSArray *userAccounts= [_accountStore accountsWithAccountType:accountType];
    ACAccount *account = [userAccounts objectAtIndex:buttonIndex -1];
    [self getTwitterTimeLineWithAccount:account];
}
       
-(void) twitterAlert
{
    UIAlertView *alert =[[UIAlertView alloc] initWithTitle:@"Twitter Authorisation" message:@"Please log into Twitter in the Settings please, then try again!" delegate:self cancelButtonTitle:@"cancel" otherButtonTitles: nil];
    [alert show];
}
-(void) alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
 	[[ActivityIndicator currentIndicator] hide];
	[[StateModel stateModel] setStartedTwitterLogin:NO];
	[[StateModel stateModel] setStartedFacebookLogin:NO];
		[mainViewController loadAccountsView];
}

-(void) getTwitterTimeLineWithAccount:(ACAccount*)account {
    //
    APHLog(@"account : %@",[account username]);
    
    NSMutableDictionary *params=[[NSMutableDictionary alloc] init];
    [params setObject:[account username] forKey:@"screen_name"];
    NSURL *url = [NSURL URLWithString:@"https://api.twitter.com/1/users/show.json?include_entities=no"];
    //TWRequest *request = [[TWRequest alloc] initWithURL:url parameters:params requestMethod:TWRequestMethodGET];
	SLRequest *request  = [SLRequest requestForServiceType:SLServiceTypeTwitter requestMethod:SLRequestMethodGET URL:url parameters:params];
	
    timeline=[[NSMutableDictionary alloc] init];
    [request setAccount:account];
    [request performRequestWithHandler:^(NSData *responseData, NSHTTPURLResponse *urlResponse, NSError *error) {
        if ([urlResponse statusCode] == 200) {
            NSError *jsonError = nil;
            id jsonResult = [NSJSONSerialization JSONObjectWithData:responseData options:0 error:&jsonError];
            if (jsonResult != nil) {
                timeline = jsonResult;
                dispatch_sync(dispatch_get_main_queue(), ^{
                    socialState=didLoadUidFromTwitter;
                    NSMutableDictionary *twitterUser=[[NSMutableDictionary alloc] init];
                    twitterUser= [[DataModel dataModel] twitterUserSettings];
                    [twitterUser setObject:[timeline objectForKey:@"id"] forKey:@"uid"];
                    [twitterUser setObject:[timeline objectForKey:@"name"] forKey:@"name"];
                    [twitterUser setObject:[timeline objectForKey:@"profile_image_url"] forKey:@"picture"];
                    [twitterUser setObject:[timeline objectForKey:@"screen_name"] forKey:@"username"];            
                    [[DataModel dataModel] setTwitterUserSettings:twitterUser]; 
                                        [self getMotivityUserUidFromTwitter];
                                    });                
            }
            else {
					[[StateModel stateModel] setStartedTwitterLogin:NO];
                NSString *message = [NSString stringWithFormat:@"Could not parse your timeline: %@", [jsonError localizedDescription]];
                [[[UIAlertView alloc] initWithTitle:@"Error" 
                                            message:message
                                           delegate:nil 
                                  cancelButtonTitle:@"Cancel" 
                                  otherButtonTitles:nil] show];
					[[StateModel stateModel] setStartedTwitterLogin:NO];
            }
        }
    }];
    
}

#2
  1. What calls loginTwitter?

  2. Does your StateModel object do anything that would cause the hang?

  3. Your willDisplayTwitterActionSheet may not be called on the main thread, since requestAccessToAccountsWithType can return on any queue. I’m not sure if this is the problem, but you should definitely make sure that you display the action sheet from the main thread.

I just tried your code with any of the unknown models commented out (stateModel, etc.), and with the action sheet call sent on the main thread and everything worked fine.


#3

Sean mate, how are you?

StateModel is just a singleton, it does nothing more.

The delay is basically loading and showing the actionSheet. I will double check threading. The curious thought is that the slow down for a tester here has been getting worst as he has been running from a deleted app, is there a way that multiple checks to see if the apps authorisation has been granted are causing a crunch or a delay? Does the accountsWithAccountType make a http request to get the accounts info?

Does location make a difference? We are testing from the Queen’s Penal Camp Australia. Its very frustrating! I wonder what factors within the whole process could be causing issues.

Thanks again Sean


#4

Sean I just noticed in the application’s Authorisation Setting on twitter.com is set to this:

Sign in with Twitter No

Could that have implications?


#5

I’m doing well, thanks for asking. Good to hear from you. Let’s try some more:

Try to remove all the accounts from Settings and then re-add. It shouldn’t be the case, but perhaps there’s something strange happening in iOS that’s affecting access to the accounts?

In iOS’ Settings / Twitter section, toggle the access from on to off. Again, this shouldn’t be the case, but it will make sure nothing strange is going on in iOS.

Another good test would be to try to disconnect the device from all networks and run the app. You should be able to display the local accounts without any network calls going out.

re: your “Sign in with Twitter” question:
Are you only using Social.framework (or Twitter.framework), or are you doing your own signing? If you’re just using the native framework you do not need to worry about the OAuth keys or any of the settings.


#6

Do this in your [actions showInView:[UIApplication sharedApplication].keyWindow]; (line 52)

[self performSelectorOnMainThread:@selector(showActionSheet:) withObject:actions waitUntilDone:YES];

-(void)showActionSheet:(UIActionSheet *)actionSheet
{
[actionSheet showInView:self.view];
}

I’m sure that is the problem :wink:

Kind regards