I have a login button in my app. While logging in there is also some data retrieved from the server in a background thread so it can take a few seconds. To let the user know he/she has to wait I display a simple activity indicator (the round loading thingy apply provides). The only problem I have now is that the user can spam the button.
I tried putting [loginButton setUserInteractionEnabled:false];
in the onclick handler and [loginButton setUserInteractionEnabled:true];
in my oncomplete handler for the data fetching. But as soon as user interaction is set to true again, all button press events that would otherwise have fired in the meantime still fire (all at once).
Since that didn't work I created a boolean loginButtonActive
and set that to false when the user presses the button. I put the rest of the button press action inside an if (loginButtonActive){}
and in the oncomplete I set the boolean to true again. This leaves me with the same problem, the messages from the button presses are sometimes delayed and will still 'press' the button again once the boolean is true again.
Here is my code so far:
- (IBAction)onLogin:(id)sender {
NSLog(@"button press");
if (loginButtonActive) {
NSLog(@"button was active");
loginButtonActive = false;
if ([usernameField.text isEqualToString:@""]) {
[GeneralFunctions showError:@"Voer uw gebruikersnaam in" withTitle:@"Fout bij inloggen"];
}
else if ([passwordField.text isEqualToString:@""]) {
[GeneralFunctions showError:@"Voer uw wachtwoord in" withTitle:@"Fout bij inloggen"];
} else {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5f];
[loginActivity setAlpha:1.0f];
loginButtonWidth = loginButton.frame.size.width;
loginButtonX = loginButton.frame.origin.x;
CGRect frame = loginButton.frame;
frame.origin.x += frame.size.width;
frame.size.width = frame.size.height;
frame.origin.x -= frame.size.width;
loginButton.frame = frame;
loginButton.text = @"";
[UIView commitAnimations];
dispatch_async(dispatch_get_main_queue(), ^{
//Login and fetch some data from the web service
me = [[User alloc] initWithLogin:[usernameField text] password:[GeneralFunctions md5:backing] version:@"1.0.0.1"];
[self restoreLoginButton];
if (me != nil) {
NSUserDefaults *prefs = [NSUserDefaults standardUserDefaults];
[prefs removeObjectForKey:@"username"];
[prefs removeObjectForKey:@"password"];
if (rememberSwitch.on) {
[prefs setObject:usernameField.text forKey:@"username"];
[prefs setObject:backing forKey:@"password"];
}
[prefs synchronize];
[self loginSuccess];
loginButton.text = @"Ingelogd";
} else {
loginButton.text = @"Inloggen";
}
});
}
} else {
NSLog(@"button was not active");
}
}
-(void)restoreLoginButton {
NSLog(@"restoring button");
dispatch_async(dispatch_get_main_queue(), ^{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5f];
[loginActivity setAlpha:0.0f];
CGRect frame = loginButton.frame;
frame.size.width = loginButtonWidth;
frame.origin.x = loginButtonX;
loginButton.frame = frame;
[UIView commitAnimations];
loginButtonActive = true;
});
}
Here is my log from spamming the button. I stopped spamming before it was done with fetching the data. I let it run untill it stopped logging. Notice how the button press
logs directly follow the restoring button
logs.
2014-04-22 11:45:32.645 Wondzorg[3097:60b] button press
2014-04-22 11:45:32.648 Wondzorg[3097:60b] button was active
2014-04-22 11:45:36.520 Wondzorg[3097:60b] restoring button
2014-04-22 11:45:36.534 Wondzorg[3097:60b] button press
2014-04-22 11:45:36.534 Wondzorg[3097:60b] button was active
2014-04-22 11:45:43.283 Wondzorg[3097:60b] restoring button
2014-04-22 11:45:43.290 Wondzorg[3097:60b] button press
2014-04-22 11:45:43.290 Wondzorg[3097:60b] button was active
2014-04-22 11:45:45.680 Wondzorg[3097:60b] restoring button
2014-04-22 11:45:45.687 Wondzorg[3097:60b] button press
2014-04-22 11:45:45.688 Wondzorg[3097:60b] button was active
2014-04-22 11:45:48.035 Wondzorg[3097:60b] restoring button
2014-04-22 11:45:48.041 Wondzorg[3097:60b] button press
2014-04-22 11:45:48.042 Wondzorg[3097:60b] button was active
2014-04-22 11:45:50.308 Wondzorg[3097:60b] restoring button
2014-04-22 11:45:50.315 Wondzorg[3097:60b] button press
2014-04-22 11:45:50.316 Wondzorg[3097:60b] button was active
How can I make sure the button does not respond to anything while I'm still fetching data?