开发者

UIAlertView Dismiss Not Really Dismissed

Below is the code I'm using to do a retry on an FBConnect session. When the [self loginToFaceBook] fires FBConnect adds a subview to 'window' which is still the UIAlert view, so when the UIAlert really dismisses it takes the FBConnect view with it. Any idea as to the best way to wait for the UIAlert view to be gone.

-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
    if([self respondsToSelector:@selector(alertContinue)]) {
        [self alertContinue];
    }
}
-(void)alertContinue
{
    SocialLiteAppDelegate *appDelegate = (SocialLiteAppDe开发者_如何学编程legate *)[[UIApplication sharedApplication] delegate];
    [appDelegate.fbSession logout];
    [self loginToFaceBook];
}


I had the same problem just now... After a big headache i solved it... :D

(if you don't need the explanation, just look at the sample code, and the few lines above it... :D )

the thing is, the alertView creates another window, makes it the key window, and places the alertView's view in it... now when you tell FBConnect to log back in, with the dialog and all, it show's it's self inside the key window. which at the time is the alertView's window.

So we just need to make the alert's window to resign it's key status. i did not find a way to manually do that, but luckily it does that for you. when? in the end of the run loop (and it actually takes a little bit of time ;) ).

the solution is pretty simple, let the alert's runloop end. you do this by running your re-login method in the background.

[self performSelectorInBackground:@selector(loginToFaceBook) withObject:nil];

but then we have two other issues to take care of:

  • as i mentioned before, it takes it a little while, to actually cleanup the alertView's mess (the window in particular). so we need to wait for it.
  • the dialog FBConnect creates has a webView inside, and the WebViews don't like being in the background... so we'll need call it in the main thread.

KennyTM has kindly suggested that it's impossible to check for other stacked alerts, i disagree... I've used this code:

BOOL shouldWait = YES ; 

// wait for the alert view to dissmiss it's self 
while (shouldWait) {

    [NSThread sleepForTimeInterval:0.1];

    UIWindow *keyWindow = [[UIApplication sharedApplication] keyWindow];
    shouldWait = [keyWindow isKindOfClass:NSClassFromString(@"_UIAlertOverlayWindow")];
}

Now i'm not sure if this is legal in the public API... but i think there are all kinds of other ways to check if the key window is the alert view's window... another one that comes to mind is to try and see it any of it's subView's is of the "UIAlertView" class... like so:

for (UIView *subView in [keyWindow subviews]) {
    if (shouldWait = [subView isKindOfClass:[UIAlertView class]) {
        break;
    }
}

anyways, i'm sure it's a solvable problem... and after i'll submit my app, and if i'll remember (i have memory problems :/ ) i'll let you guys know if apple approved any of these technics...

and the other thing you'll need to is to "show" the dialog on the main thread. but that's easy:

FBStreamDialog* dialog = [[[FBStreamDialog alloc] init] autorelease];
[dialog performSelectorOnMainThread:@selector(show) withObject:nil];

if you want to init the dialog with a session, you'll need to do that on the main thread as well...

I had a method called "showDialodWhenAppropriate" which i perform in the background. it does the waiting, and when it's appropriate, i call another method called "showTheDialog" which i call on the main thread.

Facebook should probably implement this themselves.. but until they do, have fun. :D


You may delay the action with a little time interval to let the window to have time to order out:

-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    if([self respondsToSelector:@selector(alertContinue)]) {
        [self performSelector:@selector(alertContinue) withObject:nil afterDelay:0.05];
    }
}

Of course, you need to ensure there are no other stacked alerts (which is impossible to check with public API, because those alerts may come from the system e.g. low battery, push notifications, etc.).


This code works only for animated = NO.

-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if(buttonIndex == alertView.cancelButtonIndex) { 
        exit(0); 
    }
    [alertView dismissWithClickedButtonIndex:buttonIndex animated:NO];
    if([self respondsToSelector:@selector(alertContinue)]) {
        [self alertContinue];
    }
}

-(void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex
{
//  if([self respondsToSelector:@selector(alertContinue)]) {
//      [self alertContinue];
//  }
}


Another option is to change the FBDialog.m code. Change this bit of code:

UIWindow* window = nil;//[UIApplication sharedApplication].keyWindow; // this does not work if you come from a UIAlertView!!!
if (!window) {
    window = [[UIApplication sharedApplication].windows objectAtIndex:0];
}

to

UIWindow* window = [[UIApplication sharedApplication].windows objectAtIndex:0];


Same problem but easy fix. I used a timer to trigger the fb method I was calling. I was trying to post a message to the users wall. I was triggering the method from the didDismissWithButtonIndex: also.

In the FBDialog show: method, it calls the current window and displays the new dialog box. I believe any dialog FBConnect uses does this.

I triggered the method with a timer set to half a second. It allows the Alert to close nicely and then the FBDialog box opens in the correct window. Using a switch case for the button index, I have the following working great.

    case 1:
            NSLog(@"Write On Wall");
            [self performSelector:@selector(postToWall) withObject:nil afterDelay:0.5f];
            break;

Maybe that will work also.


You need to call:

 - (void)dismissWithClickedButtonIndex:(NSInteger)buttonIndex animated:(BOOL)animated

to dismiss the alert view.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜