I am developing this iPhone app which has basic login - logout functionality. The requirement is to implement a logout action as below.
- First get the user's confirmation using a UIAlertView
- Show a log-out-in-progress alert box while logout process is handled in servers
The server logic has not been implemented yet, but i am facing problem when showing this second, in-progress alert box. The problem is, alert box is not showed and instead main thread just goes to sleep and go to the root view controller. Can any one help me with this problem.
Following is my code :
Logout action :
-(IBAction)logOut
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:@"Really Want to Log Out?"
message:@"If you continue you will be redirected to Home page,
where you have to sign in again. \n\nContinue?"
delegate:self cancelButtonTitle:@"Cancel"
otherButtonTitles:@"Continue", nil];
[alert show];
[alert release];
}
The input of the user (which button the user has clicked) will be handled as follows...
-(void)alertView:(UIAlertView *) actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if 开发者_JAVA技巧(buttonIndex == 1) {
[NSThread detachNewThreadSelector:@selector(dataProcessor)
toTarget:self withObject:nil];
[NSThread sleepForTimeInterval:3];
[self.navigationController popToRootViewControllerAnimated:YES];
} else {
// do nothing
}
}
And the dataProcessor() is implemented as follows :
-(void)dataProcessor {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Signing out...\n\nPlease Wait..."
message:nil delegate:self cancelButtonTitle:nil
otherButtonTitles: nil] autorelease];
[alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(alert.bounds.size.width / 2,
alert.bounds.size.height - 50);
[indicator startAnimating];
[alert addSubview:indicator];
[indicator release];
[alert dismissWithClickedButtonIndex:0 animated:YES];
[pool release];
}
When i using this approach this alert with the UIActivityIndicator is not shown. What happens is the welcome view controller goes black out (i think it because of [NSThread sleepForTimeInterval:3]; ) and go back to root view controller.
Also i have tried use a tag with alerts as mentioned in this post. Show Alert in clickedButtonAtIndex? But still i can not get this to work.
Please can anyone help me out? Thanks in advance.
There are quite a few things wrong here.
- Dealing with UIKit elements in a thread other than main one.
- You are creating the alert, displaying it and immediately dismissing it. Of course, in computer time this must happen mighty fast. So you wouldn't even see it.
- Blocking the UI. (Of course, this is what you seem to want.)
You should probably do it like this,
-(void)alertView:(UIAlertView *) actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 1) {
[self dataProcessor];
} else {
// do nothing
}
}
and later in dataProcessor
,
-(void)dataProcessor {
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:@"Signing out...\n\nPlease Wait..."
message:nil delegate:self cancelButtonTitle:nil
otherButtonTitles: nil] autorelease];
[alert show];
UIActivityIndicatorView *indicator = [[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
indicator.center = CGPointMake(alert.bounds.size.width / 2,
alert.bounds.size.height - 50);
[indicator startAnimating];
[alert addSubview:indicator];
[indicator release];
[self performSelector:@selector(dismissAndPop:) withObject:alert afterDelay:3.0f];
}
and declare dismissAndPop:
in .h and .m,
- (void)dismissAndPop:(UIAlertView *)alertView {
[alertView dismissWithClickedButtonIndex:0 animated:NO];
[alertView release];
[self.navigationController popToRootViewControllerAnimated:YES];
}
I've just updated your logic to show the alert view and after 3 seconds, trigger its dismissal followed by a popViewControllerAnimated:
.
You should never do code that acts on the UI anywhere else than in the main thread.
Every code that change anything on the User Interface should be done in the UI.
Also, using [NSThread sleepForTimeInterval]
is a blocking method, which is a bad practice (active wait vs. passive wait)
If you can't have a delegate method that informs you that the processing is done, and still want to wait for a fixed amount of seconds instead, use performSelector:withObject:afterDelay:
for example to call a method after a given delay ; this method will typically, for your example, dismiss your alertView and call the popToRootViewControllerAnimated
method.
Other option is to use an NSTimer for that, but performSelector:withObject:afterDelay:
should be much simple to use.
精彩评论